匿名関数の省略形


85

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

次の作品:

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

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

REPL>  (#(%) "Eh")

これは機能します:

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

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

これらは両方とも無名関数であり、ここでは両方とも1つのパラメーターを取ります。速記表記には関数が必要なのに、他の表記には必要ないのはなぜですか?

回答:


126
#(...)

の省略形です

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

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

#(%)

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

(fn [arg1] (arg1))

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

(fn [arg1] arg1)

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

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


64

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

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

#(-> %)

#(...)ディスパッチマクロを->スレッドマクロと組み合わせることにより、のような(fn [arg1] (-> arg1))ものに展開され(fn [arg1] arg1)、再びに展開されます。これは、必要なだけです。また、->and#(...)マクロの組み合わせは、ベクトルを返す単純な関数を作成するのに役立ちます。

#(-> [%2 %1])

20

あなたが使用する場合は#(...)、あなたが代わりに書いている想像することができる(fn [args] (...))など、あなたが右のパウンド後に開始括弧。

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

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

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

この完全に最小限の例を除いて、すべての無名関数が何かを呼び出すので、それについて考えると理にかなっています。したがって、実際に呼び出すために別のネストされた親のセットを要求するのは少しばかげています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.