LINQ to ObjectのメソッドをJavaScriptの個別のモジュールとして使うためのライブラリ

LINQ to ObjectのメソッドをJavaScriptの個別のモジュールとして使うことのできるライブラリを作った。 これは元々Feedponで利用するために作ったのもので、現在はライブラリ単体として切り出している。

@emonkak/enumerable

なお、今回特に解説しないが本ライブラリはPHP版のものも存在する。

Emonkak\Enumerable

設計

この手のシーケンス処理のためのライブラリは膨大なメソッド(関数)を提供するので、そのライブラリに依存するスクリプトのサイズが大きくなりがちだ。 そのため、lodashRxJSなどのライブラリは個別のメソッドをモジュールとしても提供している。 個別に提供することで必要なものだけを読み込むようになるので、スクリプトのサイズ減らすことができるからだ。

今回作成した@emonkak/enumerableも同様で、メソッドを個別にモジュールとして提供している。 さらに、それらのモジュールが他のモジュールになるべく依存しないようにすることで、スクリプトサイズの増加を最小限に抑えている。

では、lodashとの違いはどこにあるのかというと、APILINQベースであるということがまずある。 LINQAPIは一般的なシーケンス処理の設計とは異なり、Select() Where() などSQL文を彷彿とさせる命名がなされている。 慣れていないと少々とっつきにくいが、APIとしての機能性はとても優れているように思う。 特に Join()GroupJoin() のような結合処理ができるのはLINQならではで、他のライブラリ等だとあまり提供されない。 実際に開発する動機となったのはこの2つのメソッドが必要になったからだ。

もう一つの違いとして、@emonkak/enumerableではGeneratorを使って実装されたIteratorをターゲットにしたAPIなので、シーケンス処理が遅延される。 そのため、返り値として配列が必要な場合は適宜変換が必要だ。 Generatorを使っているのでサポート環境が限られるが、モダンブラウザではサポートが進みつつある。 サポート環境を絞ればトランスパイルなしで利用できるだろう。

使用例

import select from '@emonkak/enumerable/select';

Array.from(select.call([1, 2, 3], (x) => x * 2));  // => [2, 4, 6]

This-Binding Syntaxを使うことでメソッドチェインをすることができる。

import select from '@emonkak/enumerable/select';
import where from '@emonkak/enumerable/where';
import toArray from '@emonkak/enumerable/toArray';

[1, 2, 3]
    ::where((x) => x % 2 === 0)
    ::select((x) => x * 2)
    ::toArray();  // => [4]

しかし、This-Binding Syntaxはまだ提案段階なのでトランスパイルなしでは使用することはできない。 代替手段として拡張モジュールを使用することができる。 拡張モジュールは読み込むと、Enumerable クラスにメソッドが追加される。

import Enumerable from '@emonkak/enumerable';

import '@emonkak/enumerable/extensions/select';
import '@emonkak/enumerable/extensions/where';
import '@emonkak/enumerable/extensions/toArray';

new Enumerable([1, 2, 3])
    .where((x) => x % 2 === 0)
    .select((x) => x * 2)
    .toArray();  // => [4]

@emonkak/enumerable

PDOにInterface欲しい

PHPの色々なフレームワークでDatabase Driverのラッパーが量産されているのが不毛に思った。 ここに共通化されたインターフェイスがあればフレームワークの違いを気にせず色々できるのになと。

そこで、PSR-3のLoggerのように標準化できないのかなと思って調べてみると、DoctrineのDBALが目に付いた。

ソースを読んでみると、DBALのConnectionインターフェイスPDOのサブセットになっている。 そうすると、PDOに対する実装であるPDOConnectionConnectionに対して実装を宣言するだけで済むわけだ。

PDOインターフェイスとして定義することで、PDOの機能をそのまま同じインターフェイスで使うことができるし、PDOを使う時には不要な抽象化レイヤーを挟まないのでシンプルでいいなと。 PDOは事実上の標準なので多くの場合これで必要十分だと思う。

しかしながら、DBALにはクエリビルダーなど不要な機能も含まれているしdoctrin/commonへの依存もある。Connection部分だけ抜きだしたpackageがあればいいのだけど、今の所ないようだった。

ということでPDOのサブセットとしてのインターフェイスだけを提供するcomposerのpackageを作りました。

https://github.com/emonkak/pdo-interface

PHPでフィボナッチ数列を出力するソースコードを出力するプログラム

Quineみたいなものだけど、自身のソースコードを次々に書き換えて
それを新たに起動したPHPプロセスに標準入力として与えている。

fib.php

<?php
function php($input) {
    $process = proc_open('php', array(array('pipe', 'r'), array('pipe', 'w')), $pipes);
    if (is_resource($process)) {
        fwrite($pipes[0], $input);
        fclose($pipes[0]); 
    
        $output = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        proc_close($process);
    
        return $output;
    }
}
function callback($output) {
    $n = 50;
    $lines = explode("\n", trim($output));
    $count = count($lines);
    $lines[] = end($lines) + prev($lines);
    $f = __FILE__;
    $s = file_get_contents($f);
    $s = preg_replace("/__FILE__[;]/", "'$f';", $s);
    $s = preg_replace('/0\n1\n/', implode("\n", $lines), $s);
    return $count < $n ? php($s) : end($lines);
}
ob_start("callback") ?>
0
1
<?php ob_end_flush() ?>

Result

$ time php fib.php 
12586269025
php fib.php  0.51s user 0.28s system 92% cpu 0.851 total

あなたが学ぶべき10のプログラミング言語

純粋関数型言語は当然学ばなければなりません。
副作用の分離とモナドによる抽象化は本当のプログラマーなら知っておくべきでしょう。
遅延評価のメリット・デメリットとそれを活かしたアルゴリズムも重要です。

  • Scala

オブジェクト指向と関数型の機能を合わせ持ったマルチパラダイム言語のScalaを学ぶことは、あなたにとって新たな知見となるでしょう。
Twitterのインフラで使われるなど実績も十分で、現在のプログラマーにとっては当然のように使えるべき言語の1つです。
Haskellもまたそうですが、Scalaは型が強力なので型レベルプログラミングを学び、コンパイル時のエラー検出について考えてみるのもよいでしょう。

マルチコアのCPUが当たり前になった現在では、難しい並列処理をいかにして簡潔に実現するのかというのは非常に重要なテーマです。
Erlangは並列処理を念頭において開発された言語で、アクターモデルによる並列処理が特徴です。
アクターモデルによる新しい並列処理のアプローチは今後必ず重要になってくるので当然学ぶべきでしょう。
Rubyライクな記述のできるElixirを学ぶのもいいかもしれません。

HTML5が普及してWebアプリケーションの重要性増しており、JavaScriptの重要性もまた非常に高まっています。
プロトタイプベースのオブジェクト指向や、プロトタイプチェーンによる継承など、クラスベースのオブジェクト指向と違ったアプローチは学ぶ価値があるでしょう。
また関数が第一級のオブジェクトなので関数型のような記述も可能です。
関数型言語で学んだ知見はここでも多いに役立つでしょう。

歴史ある関数型のLISPやその方言のSchemeなどはプログラマーを名乗るのであれば書けて当然の言語でしょう。
S式による一貫した記法によってコードそものものを第一級のオブジェクトとして扱える柔軟性は他にはない素晴しいものです。
マクロによるプログラミングについても大いに学ぶことがあるでしょう。

歴史ある関数型言語MLから派生して生まれた、オブジェクト指向の機能を持った関数型言語です。
純粋な関数型言語Haskellとはまた少し違ったアプローチのOCamlを学ぶことで、関数型言語に対する理解がさらに深まるでしょう。

  • Coq

プログラムにはバグが付きものですが、バグを無くすにはどうすればいいでしょう。
テストを書けばテストケースに漏れがない限りはプログラムの品質を保証できます。
しかし、定理証明系のCoqを使えば、プログラムの動作を完全に証明することもできます。
テスト駆動開発、ビヘイビア駆動開発に続く、証明駆動開発について学ぶことは新しい知見となるでしょう。

Templateを使ったGenericプログラミングや、constexprによるコンパル時実行、型推論、ラムダ式など先進的な機能がたくさん詰ったC++は是非学んでおきたい言語です。
ある程度の規模の高速なネイティブプログラムを開発しようと思うとCでは非力すぎるため、多くの場合C++が最良の選択肢でしょう。
高速なネイティブプログラムが必要となる場面というのは未だ多く、学ばなければならない言語の1つでしょう。

Luaはプログラムに組み込んで使うこと目的として開発されたJavaScriptライクなスクリプト言語です。
言語として特徴的なのは途中で処理を止めて再開することができるコルーチンを持っている所でしょう。
スクリプト言語でありながら動作が非常に高速で、プログラムに組込むDSLとして最適と言えます。
例えばプログラムの設定ファイルの記述をLuaで柔軟に行なえるようにするなど、DSLを組込みこんだ設計というのは学ぶべき価値があるものです。