41

Clojureの`->theadingマクロは、提供されたすべての関数を特定の引数に適用することを理解しています。ただし、無名関数では機能しないようです。例えば:

user> (-> 4 inc inc dec)
5

だが:

user> (-> 4 #(+ % 1) #(- % 1) #(+ % 1))

エラーを返します:

clojure.lang.Symbol cannot be cast to clojure.lang.IPersistentVector
[Thrown class java.lang.ClassCastException]

誰かが回避策を知っているなら、それは役に立ちます。ありがとう!

4

3 に答える 3

52

Clojureマクロで無名関数を持つことができます。いくつかの括弧が欠落しているため、問題が発生しています。:)あなたの例は以下で編集されています。

(-> 4 (#(+ % 1)) (#(- % 1)) (#(+ % 1)))
于 2012-05-24T15:18:36.703 に答える
32

(これは私がコメントで投稿した質問への回答に基づいています)。

マクロは各引数を取り、->必要に応じてリストにし(「raw」関数を引数なしに適用し、に変換myfunc(myfunc)ます)、最初の引数を->2番目の引数としてこれらの各リストに挿入します。

おおざっぱになり(-> foo myfunc)ます(-> foo (myfunc))(myfunc foo)

これはすべて、のドキュメントで->説明されています。

匿名関数の問題は、ここで説明されているように(下にスクロールして)リーダーマクロによって生成されることです。これは、(通常のマクロ展開の前に#(...))に変換されることを意味します。これは問題ありませんが、重要なことに、すでにリストになっています。(fn [...] ...)

したがって、マクロは、実際には関数定義(両方ともリスト)に遭遇しているときに、無名関数がすでに適用されていると信じています。そして、「余分な」括弧を追加すると(他の回答で前述したように)、無名関数が引数なしに適用されます。

この直感的でない動作の理由は、マクロで使用されるdwim(do-what-i-mean、dwim-wittedではありませんが...)ヒューリスティックが->追加され、必要ではなく「裸の」関数を提供できるようにするためです。それらをリストで囲むことによって引数なしに適用することは、単なるヒューリスティックであり、単にリストをテストするだけであり、リーダーマクロによって作成された関数定義によって混乱します。

[私の悪い意見で->は、実装が不十分であり、代わりに関数適用のみを受け入れるのではなく、すべての「裸の」関数を拒否する必要があります。そうすれば、より一貫性があるように見えます。そうでなければ、少なくともドキュメントはより明確になり、リストに物を置くことの背後にある動機付けのセマンティクスを説明することができます。]

于 2012-05-25T16:29:49.527 に答える
4

あなたの特定のケースは、以下を使用するだけで解決できたはずです。

(-> 4 (+ 1) (- 1) (+ 1))

ここで、スレッドの最初のマクロ->は、前のステップの結果を「現在の」関数の最初の引数として挿入します。

->混乱は、関数ではなくマクロであり、他の回答で説明されているように、この場合は引数の扱いが非常に異なるという事実から生じます。

于 2016-01-24T18:41:53.133 に答える