85

短縮表記 #(..) を使用する無名関数について理解できないことがあります。

以下の作品:

REPL>  ((fn [s] s) "Eh")
"Eh"

しかし、これはしません:

REPL>  (#(%) "Eh")

これは機能します:

REPL> (#(str %) "Eh")
"Eh"

私が理解していないのは、(#(%) "Eh")が機能せず、同時にstr((fn [s] s) "Eh")で使用する必要がない理由です

どちらも無名関数であり、ここでは 1 つのパラメーターを取ります。短縮記法には関数が必要で、他の記法には必要ないのはなぜですか?

4

4 に答える 4

126
#(...)

の省略形です

(fn [arg1 arg2 ...] (...))

(argN の数は、本体に含まれる %N の数によって異なります)。だからあなたが書くとき:

#(%)

それは次のように翻訳されます:

(fn [arg1] (arg1))

これは、次のような最初の無名関数とは異なることに注意してください。

(fn [arg1] arg1)

バージョンは arg1 を値として返します。短縮形を展開したバージョンは、それを関数として呼び出そうとします。文字列は有効な関数ではないため、エラーが発生します。

短縮形は本体の周りに一連の括弧を提供するため、単一の関数呼び出しまたは特別なフォームを実行するためにのみ使用できます。

于 2012-11-03T01:33:10.913 に答える
65

他の回答がすでに非常にうまく指摘しているように、#(%)投稿した は実際には のようなものに展開されますが(fn [arg1] (arg1))、これは とまったく同じではありません(fn [arg1] arg1)

@John Flatness は、 をそのまま使用できると指摘しましたが、dispatch マクロを使用しidentityて記述する方法を探している場合は、次のように実行できます。identity#(...)

#(-> %)

#(...)ディスパッチ マクロと->スレッド マクロを組み合わせることで、 のようなもの(fn [arg1] (-> arg1))に展開され、それが再び に展開され(fn [arg1] arg1)ます。->また、ベクトルを返す単純な関数を記述するのに、と#(...)マクロの組み合わせが役立つこともわかりました。たとえば、次のようになります。

#(-> [%2 %1])
于 2012-11-03T05:30:46.007 に答える
21

を使用すると、ポンドの直後に開始した括弧を含めて、#(...)代わりに を書いていることが想像できます。(fn [args] (...))

したがって、動作しない例は次のように変換されます。

((fn [s] (s)) "Eh")

文字列「Eh」を呼び出そうとしているため、明らかに機能しません。関数がの代わりにあるため、の例がstr機能します。str に強制されないため、最初の例に近いアナログになります。(str s)(s)(identity s)

この完全に最小限の例を除いて、すべての匿名関数は何かを呼び出すため、実際に呼び出しを行うために別のネストされた括弧のセットを要求するのは少しばかげているため、考えてみれば理にかなっています。

于 2012-11-03T01:33:01.710 に答える