なぜこの Clojure コードは次のようになるのでしょうか。
user=> (map (constantly (println "Loop it.")) (range 0 3))
次の出力が生成されます。
Loop it.
(nil nil nil)
関数を 3 回評価することの副作用として、"Loop it" を 3 回出力することを期待しています。
なぜこの Clojure コードは次のようになるのでしょうか。
user=> (map (constantly (println "Loop it.")) (range 0 3))
次の出力が生成されます。
Loop it.
(nil nil nil)
関数を 3 回評価することの副作用として、"Loop it" を 3 回出力することを期待しています。
constantly
その引数を複数回評価しません。これはマクロではなく関数であるため、引数はconstantly
実行前に1回だけ評価されます。すべてconstantly
は、(評価された)引数を取り、呼び出されるたびに指定された値を返す関数を返すことです(前述したように、引数はconstantly
実行される前にすでに評価されているため、何も再評価しません)。
範囲内のすべての要素を呼び出すだけ(println "Loop it")
の場合は、それを。の代わりにマップする関数として渡す必要がありconstantly
ます。実際には、評価された式ではなく、関数として渡す必要があることに注意してください。
繰り返し使用し、ラムダ式を使用することで、意図に近い動作を得ることができます。
例えば:
(repeatedly 3 #(println "Loop it"))
REPL にいる場合を除き、これは adorun
などで囲む必要があります。repeatedly
怠け者です。
sepp2k が正しく指摘してconstantly
いるように、関数であるため、その引数は一度だけ評価されます。
ここで行っていることを達成するための慣用的な方法は、次を使用することdoseq
です。
(doseq [i (range 0 3)]
(println "Loop it."))
または、代わりdotimes
に(この特定のケースでは、によって生成されたシーケンスを実際に使用していないため、もう少し簡潔で効率的ですrange
):
(dotimes [i 3]
(println "Loop it."))
これらのソリューションは両方とも非遅延です。これは、副作用のためにコードを実行するだけの場合に必要なことです。