宏 - >匿名函数

S4M*_*S4M 33 macros lambda clojure

我理解宏 - >在clojure中应用了为给定参数提供的所有函数.但是,它似乎不适用于匿名函数(在clojure 1.3.0上).例如:

user> (-> 4 inc inc dec)
5
Run Code Online (Sandbox Code Playgroud)

但:

user> (-> 4 #(+ % 1) #(- % 1) #(+ % 1))
Run Code Online (Sandbox Code Playgroud)

返回错误:

clojure.lang.Symbol cannot be cast to clojure.lang.IPersistentVector
[Thrown class java.lang.ClassCastException]
Run Code Online (Sandbox Code Playgroud)

如果有人知道解决方法会有所帮助.谢谢!

Ank*_*kur 41

您可以在Clojure宏中使用匿名函数.你遇到了问题,因为你遗漏了一些括号.:)您的示例在下面编辑.

(-> 4 (#(+ % 1)) (#(- % 1)) (#(+ % 1)))
Run Code Online (Sandbox Code Playgroud)

  • 查看`macroexpand`以确切知道为什么需要额外的parens才能工作...这是有趣的东西:) (3认同)
  • 这不是一个错误吗?您不应该了解使用api的实现细节. (3认同)

and*_*oke 29

(这是基于我在评论中发布的问题的答案).

->宏接受每个参数,使其成为一个列表中,如果必要的(在应用"原始"功能,以无参数-转换myfunc(myfunc)),然后插入的第一个参数->为在每个这些列表中的第二个参数.

因此(-> foo myfunc)变得(-> foo (myfunc))变得(myfunc foo)大致.

这些都在文档中->描述.

匿名函数的问题在于它们是由读者宏生成的,如此处所述(向下滚动).这意味着将#(...)其转换(正常的宏扩展之前)(fn [...] ...).这很好,但是,关键的是,已经是一个清单.

所以宏认为匿名函数已经被应用,实际上它正在遇到一个函数定义(两个都是列表).并添加"额外"的parens - 如上面在另一个答案中所述 - 将匿名函数应用于无args.

这种不直观的行为的原因是宏所使用的dwim(做什么意思,不是dwim-witted,虽然......)启发式->,添加了允许你提供"裸"功能而不是要求通过将它们包含在列表中来将它们应用于无args 只是一种启发式方法 - 它只是测试列表 - 并且被读取器宏创建的函数定义所混淆.

[我的脾气暴躁,->实施得很差,应该拒绝所有"裸"功能,而只是接受功能应用; 然后它会显得更加一致.如果没有,那么至少文档可以更清楚,解释将事物放入列表背后的激励语义.


mru*_*cci 5

您的具体案例可以简单地使用以下方法解决:

(-> 4 (+ 1) (- 1) (+ 1))
Run Code Online (Sandbox Code Playgroud)

其中线程优先宏->负责将上一步的结果作为第一个参数插入“当前”函数中。

造成混乱的原因是它->不是一个函数而是一个宏,并且在这种情况下参数的处理方式非常不同,正如其他答案所解释的那样。