なぜ人々は
(for [x '(1 2 3)] (* 2 x))
の代わりに の ようなリスト内包表記を好むの(map #(* %1 2) '(1 2 3))
ですか?
この種のプログラミングに利点はありますか?
1.読みやすいですか?
2.場合によっては速いですか?3. 特定の種類の操作やデータ構造に適していますか?
なぜ人々は
(for [x '(1 2 3)] (* 2 x))
の代わりに の ようなリスト内包表記を好むの(map #(* %1 2) '(1 2 3))
ですか?
この種のプログラミングに利点はありますか?
1.読みやすいですか?
2.場合によっては速いですか?3. 特定の種類の操作やデータ構造に適していますか?
あなたの例では、利点はありません。ただし、一般に、 2 つ (またはそれ以上) のシーケンスを結合する場合、または何らかのフィルタリングをfor
行う必要がある場合に便利です。for
:let
:when
map
filter
リスト内包表記は、標準の関数型プログラムに対する単なる「糖衣構文」ですが、リストに対する一般的な操作を直感的に読み取ることができます。-ガイ・ラパルム
彼らの唯一の目的は、読みやすさの向上です。それらを使用することによる大幅なパフォーマンスの向上は期待しないでください。
このペーパーは、Lispのような言語でリスト内包表記を実装するための洞察を提供します。
まず第一に、リスト内包表記は単なる構文糖衣であるため、読みやすさ以外に固有の違いはないはずです。
ただし、リスト内包表記は、実際には少なくとも 3 つの高階関数、つまりとを1 つの構文に統合することに注意してください。したがって、これらの複雑な組み合わせが必要になるような自明ではないケースでは、構文には読みやすさの大きな利点があります。map
filter
concatMap
それに加えて、値バインディングを便利に使用して結果を保存し、物事をさらに明確にすることができます。
[ (x, y) | x <- [1..10],
y <- [1..10],
let dist = (x - 5)² + (y - 5)²,
dist < 10² ]
とにかく、リストの内包表記は、単にリストを処理するよりもはるかに一般的なものにすることができます。基本的に、Monad
統一された便利な構文を使用してすべてを処理できます。たとえば、F# では、これを任意のプログラム フローの制御に拡張することさえできます。
第二に、通常の高階関数よりもさらに抽象的であるため、リスト内包表記は実際には高速である可能性があります。これは、コンパイラーが最適化の法則を利用できるためです。そうでなければ、プログラマーが考慮する必要があります。
[ x + 1 | x <- numbers, even x ]
直訳すると、
map (\x -> x + 1) (filter even x)
リストは2 回繰り返され、価値のない中間結果が生成されます。
ただし、コンパイラは上記のパターンを認識して最適化し、直接最適化されたfilterMap
バージョンを生成できます。
リスト内包表記は、より複雑な方法でシーケンスを反復処理する必要がある場合に使用されます。あなたの例ではそれらは同じなので、読みやすいので地図をお勧めします。
たとえば、これを 行うとマップカントが醜くなります。
(for [x '(1 2 3) y '(3 2 1)] (* 2 x y))
これが Clojure に関する質問であることは承知していますが、Martin Odersky 氏らによる本「Programming in Scala」には、for
内包表記が関数map
とfilter
関数にどのようにマップされるかについての素晴らしい議論があります。