関数型言語、主に Scala には精通していますが、Clojure にはまったく慣れていません。
Clojure でコレクションを操作する慣用的な方法を理解しようとしています。などの関数の動作に特に混乱していmap
ます。
map
Scala では、これが理にかなっている限り、元のコレクションと同じ型のコレクションを常に返すように、細心の注意を払って作成されます。
List(1, 2, 3) map (2 *) == List(2, 4, 6)
Set(1, 2, 3) map (2 *) == Set(2, 4, 6)
Vector(1, 2, 3) map (2 *) == Vector(2, 4, 6)
代わりに、Clojure では、私の知る限り、熱心なデータ構造で呼び出された場合でも、map
orなどのほとんどの操作は遅延しています。filter
これは奇妙な結果をもたらします
(map #(* 2 %) [1 2 3])
ベクトルの代わりに遅延リスト。
私は一般的に怠惰な操作を好みますが、上記は紛らわしいと思います。実際、ベクトルは、リストでは保証されない特定のパフォーマンス特性を保証します。
上記の結果を使用して、その最後に追加するとします。私が正しく理解していれば、結果は追加しようとするまで評価されず、評価されてベクトルではなくリストが取得されます。そのため、最後に追加するにはそれをトラバースする必要があります。もちろん、後でベクトルに変換することもできますが、これは面倒で見落とされる可能性があります。
私が正しく理解していれば、map
ポリモーフィックであり、ベクトルのベクトル、リストのリスト、ストリームのストリーム (今回は遅延セマンティクスを使用) などを返すように実装することは問題ありません。Clojure の基本設計とそのイディオムについて、何かが欠けていると思います。
clojure データ構造に対する基本的な操作が構造を無効にしない理由は何ですか?