匿名函数简写
有一些我不明白匿名函数使用短符号#(..)
以下工作:
REPL> ((fn [s] s) "Eh") "Eh"
但是这不是:
REPL> (#(%) "Eh")
这工作:
REPL> (#(str %) "Eh") "Eh"
我不明白的是为什么(#(%)“Eh”)不起作用,同时我也不需要用str ((fn [s] s))“Eh”)
它们都是匿名函数,在这里它们都是一个参数。 为什么速记符号需要一个函数,而另一个符号不需要?
#(...)
是速记
(fn [arg1 arg2 ...] (...))
(argN的数量取决于你在体内有多less%N)。 所以当你写:
#(%)
它被翻译成:
(fn [arg1] (arg1))
请注意,这与您的第一个匿名函数有所不同,如下所示:
(fn [arg1] arg1)
您的版本将arg1作为值返回,扩展速记所带来的版本会尝试将其作为函数调用。 你得到一个错误,因为一个string不是一个有效的函数。
由于简写在身体周围提供了一组括号,因此只能用于执行单个函数调用或特殊forms。
由于其他答案已经很好的指出了,你发布的#(%)
实际上扩展到了(fn [arg1] (arg1))
,这与(fn [arg1] arg1)
。
@John Flatness指出,你可以使用identity
,但是如果你正在寻找使用#(...)
dispatchmacros写identity
方法,你可以这样做:
#(-> %)
通过将#(...)
dispatchmacros与->
线程macros相结合,它将被扩展为(fn [arg1] (-> arg1))
,它又扩展到(fn [arg1] arg1)
想要你想要的。 我也发现->
和#(...)
macros组合有助于编写返回向量的简单函数,例如:
#(-> [%2 %1])
当你使用#(...)
,你可以想象你正在写(fn [args] (...))
, 包括刚刚在英镑之后开始的圆括号。
所以,你的非工作的例子转换为:
((fn [s] (s)) "Eh")
这显然不起作用,因为你试图调用string“呃”。 你的例子用str
工作,因为现在你的函数是(str s)
而不是(s)
。 (identity s)
会更接近你的第一个例子,因为它不会被强迫。
如果你仔细想一下,这是有道理的,因为除了这个最简单的例子之外,每个匿名函数都会调用一些东西 ,所以要求另外一个嵌套的parens实际地调用它会有点愚蠢。