Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

List in JSを更新しました

github.com

以前、List in JSというライブラリを作っていたのですが、同じようなライブラリが存在していたこと、実装がつまったことで放置していました。が、ありがたいことに星を7つもつけていただけたので、このままでは申し訳ないと奮い立ち、アップデートを行いました。

大きな変更点

まず、以前つまった無限リストを実装しました。無限リストは.cycle()や.repeat()、.iterate()などを使うことで生成できます。無限リストに対し.tail()や.head()、.take()などを行うことができます。

また、無限リストを継承する、という形でリストを再定義しました。リスト⊂無限リストですので直感的ですね。

Generatorの大活躍

Generatorを本当によく使いました。Generatorなしでは成り立たないくらい依存しています。無限リストもGeneratorなら簡潔に記述でき、.tail()や.head()といったメソッドもGeneratorを使うことでかんたんに実現できました。

今つまっている点

どうしても、遅延評価なしでは実現できないところが出てきてしまってなやんでいます。

foldr1 (&&) $ repeat False

この簡潔な式ですらList in JSでは表現できません。

List.repeat(false).foldr((a, b)=> a && b, true); // 無限ループを起こす

なぜかというと、foldrが

foldr(f, acc) {
    if (this.generator().next().done) return acc; // 空のリストであるとき
    return f(this.head(), this.tail().foldr(f, acc));
}

という実装になっており、this.tail().foldr(f, acc) を必ず評価してしまうのです。

List.repeat(false).foldr((lazyA, lazyB)=> lazyA.value() && lazyB.value(), true);

とできたらいいのですが、そうなるとfoldrを使うたびに

list.foldr1(f).value();

と書かなければいけなくなり、まどろっこしくなります。何より、ライブラリ使用者に lazyA.value() と書かせるのもいかがなものでしょうか…

やはり言語仕様でサポートしてくれないと、どうしても気持ちが悪い解決策しかできず詰まっています。どうしたらいいんですかね…