2012-11-03 104 views
76

有件事情我不明白如何使用短符號#(..)匿名函數速記

以下作品匿名函數:

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

但這並不:

REPL> (#(%) "Eh") 

這工作:

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

我不明白的是爲什麼(#(%)「Eh」)不起作用,同時我也不需要使用str in ((fn [s] s)「嗯「)

他們都是匿名函數,他們都採取,在這裏,一個參數。爲什麼簡寫符號需要一個函數,而另一個符號不需要?

回答

115
#(...) 

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

(其中ARGN的數量取決於你有多少個%N在體內)的簡寫。所以,當你寫:

#(%) 

它翻譯成:

(fn [arg1] (arg1)) 

注意,這是你的第一個匿名函數,這就好比是不同的:

(fn [arg1] arg1) 

你的版本返回Arg1爲一個值,擴展速記產生的版本會嘗試將其稱爲函數。你得到一個錯誤,因爲一個字符串不是一個有效的函數。

由於速記在身體周圍提供了一組括號,因此它只能用於執行單個函數調用或特殊形式。

18

當您使用#(...)時,您可以想象自己寫的是(fn [args] (...)),,其中包括您在英鎊之後開始的括號。

所以,你不工作的例子轉換爲:

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

這是因爲你試圖呼叫字符串「嗯」顯然是行不通的。你的例子str的作品,因爲現在你的功能是(str s)而不是(s)(identity s)會更接近你的第一個例子,因爲它不會強迫str。

這是有道理的,如果你仔細想想,因爲比這完全小例子,其他的,每一個匿名函數會調用東西,所以這會是一個有點傻,要求另一組嵌套括號的實際上使一個電話。

56

至於其他的答案已經非常漂亮指出的那樣,你居然張貼#(%)擴展到像(fn [arg1] (arg1)),這一點也不一樣(fn [arg1] arg1)

@約翰平整度指出,你可以使用identity,但如果你正在尋找一種方式使用#(...)調度宏寫identity,你可以做這樣的:

​​

通過結合#(...)調度宏與-> threading macro它被擴大到像(fn [arg1] (-> arg1)),它再次擴大到(fn [arg1] arg1),這只是想你想要的東西。我還發現->#(...)宏組合有助於編寫返回向量的簡單函數,例如:

#(-> [%2 %1])