web-dev-qa-db-ja.com

無名関数の速記

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

次の作品:

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

しかし、これはそうではありません:

REPL>  (#(%) "Eh")

これは動作します:

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

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

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

84
Cedric Martin
#(...)

の略記です

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

(argNの数は、本文にある%Nの数に依存します)。だからあなたが書くとき:

#(%)

それはに翻訳されます:

(fn [arg1] (arg1))

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

(fn [arg1] arg1)

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

略記は本文を囲む括弧のセットを提供するため、単一の関数呼び出しまたは特別な形式を実行するためにのみ使用できます。

123
Barmar

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

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

_#(-> %)
_

#(...)ディスパッチマクロと _->_スレッドマクロ を組み合わせることにより、_(fn [arg1] (-> arg1))_のようなものに展開され、再び_(fn [arg1] arg1)_に展開されます。それはあなたが欲しかっただけです。また、_->_および#(...)マクロコンボは、ベクトルを返す単純な関数を作成するのに役立ちます。たとえば:

_#(-> [%2 %1])
_
62
DaoWen

#(...)を使用すると、代わりに(fn [args] (...))含むポンドの直後に開始した括弧。

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

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

call文字列 "Eh"をしようとしているため、明らかに機能しません。 strを使用した例は、関数が(str s) の代わりに (s)(identity s)はstrに強制されないため、最初の例に似たものになります。

この完全に最小限の例以外では、すべての匿名関数がsomethingを呼び出すので、考えてみると理にかなっています。電話を掛ける。

20
John Flatness