2012-07-23 15 views
6

なぜClojureのコードのこのビット:Clojureは常に、マップ機能

user=> (map (constantly (println "Loop it.")) (range 0 3)) 

収量この出力:

Loop it. 
(nil nil nil) 

が、私はそれが側として「ループそれを」三回を印刷するように期待関数を3回評価する効果。

答えて

9

constantly引数を何度も評価しません。これは関数であり、マクロではないため、引数はconstantlyが実行される前に一度だけ評価されます。すべてconstantlyは、(評価された)引数をとり、呼び出されるたびに(指定された値を返す関数を返します)(constantlyが実行される前に引数が評価されているため、何も再評価しません)。

範囲内のすべての要素に対して(println "Loop it")を呼び出す場合は、constantlyではなく、マップする関数として渡す必要があります。実際には評価された式ではなく関数として渡す必要があることに注意してください。

+0

ソースを参照してください。これは勝者のように見えます。 – Mike

+0

私が必要としない引数を明示的に渡すのを避けるために絶えず使用しようとしていました。しかし、これで解決します。 – Mike

+10

副作用だけが必要な場合は、 'doseq'または' dotimes'を使うべきです。 'map'は怠惰なので、' doall'や 'dorun'で強制しない限り、望む結果を得ることはできません。 –

3

repeatedlyとラムダ式で、あなたの意図に近い行動を得ることができます。例えば

(repeatedly 3 #(println "Loop it")) 

あなたはREPLにいる場合を除き、これはdorunまたは同様に囲まれる必要があります。 repeatedlyは遅延です。

+0

ラムダは私が渡す引数を使いたいのでコンパイルできません。この場合、私はむしろ議論を無視したいと思う。 – Mike

+0

私はあなたに類似した使用例を追加しました。 – sortega

+0

ああ、それははるかに理にかなっている。ありがとう! – Mike

3

sepp2kが正しく指摘したように、constantlyは関数なので、その引数は1回だけ評価されます。

あなたはここで何をしているかを達成するための慣用的な方法は、doseqを使用することです:

(doseq [i (range 0 3)] 
    (println "Loop it.")) 

または代わりdotimes(あなたが実際に使用していないとして、この特定のケースでは、もう少し簡潔かつ効率的ですrangeによって生成シーケンス):これらのソリューションの

(dotimes [i 3] 
    (println "Loop it.")) 

どちらも、あなただけの副作用のためにいくつかのコードを実行している場合、あなたが望むものはおそらくである、非怠惰です。

関連する問題