Lambda 线程宏->;使用匿名函数
我知道Clojure中的`->theadeding宏将提供的所有函数应用于给定的参数。但是,它似乎不适用于匿名函数。例如:Lambda 线程宏->;使用匿名函数,lambda,clojure,macros,Lambda,Clojure,Macros,我知道Clojure中的`->theadeding宏将提供的所有函数应用于给定的参数。但是,它似乎不适用于匿名函数。例如: user> (-> 4 inc inc dec) 5 但是: 返回错误: clojure.lang.Symbol cannot be cast to clojure.lang.IPersistentVector [Thrown class java.lang.ClassCastException] 如果有人知道一个解决方法,这将是有益的。谢谢 您可以在Clo
user> (-> 4 inc inc dec)
5
但是:
返回错误:
clojure.lang.Symbol cannot be cast to clojure.lang.IPersistentVector
[Thrown class java.lang.ClassCastException]
如果有人知道一个解决方法,这将是有益的。谢谢 您可以在Clojure宏中使用匿名函数。您遇到了问题,因为缺少一些括号。:)下面对您的示例进行了编辑
(-> 4 (#(+ % 1)) (#(- % 1)) (#(+ % 1)))
(这是基于我在评论中发布的问题的答案)
->
宏接受每个参数,必要时将其列为一个列表(将“原始”函数应用于无参数-将myfunc
转换为(myfunc)
),然后将第一个参数插入到->
,作为每个列表中的第二个参数
因此,(->foo myfunc)
大致变成了(->foo(myfunc))
变成了(myfunc foo)
这些都在本文中描述
匿名函数的问题在于,它们是由读卡器宏生成的。这意味着#(…)
将(在正常宏扩展之前)转换为(fn[…])
。这很好,但关键的是,这已经是一个清单了
因此,宏认为匿名函数已经被应用,而实际上它遇到了函数定义(两者都是列表)。并且添加“额外”参数(如上在另一个答案中所述)将匿名函数应用于no参数
这种非直观行为的原因是,->
宏使用的dwim(do-what-i-means,而不是dwim-witted,尽管…)启发法允许您提供“裸”函数,而不是通过将它们包含在列表中来要求您将它们应用于无参数,它只是一种启发式方法——它只是测试一个列表——并且被reader宏创建的函数定义弄糊涂了
[在我的坏脾气看来,
->
实现得很差,应该拒绝所有“裸”函数,而不是只接受函数应用程序;这样看起来会更一致。如果不是这样,那么至少文档可以更清晰,解释将内容放入列表背后的激励语义。]您的具体案例可以通过以下方式解决:
(-> 4 (+ 1) (- 1) (+ 1))
其中,线程第一个宏->
负责将上一步的结果作为第一个参数插入“current”函数中
混淆是因为
->
不是一个函数而是一个宏,在本例中,参数的处理方式与其他答案所解释的非常不同。是的,它现在可以工作了!我担心宏->不喜欢匿名函数,但简单地添加paren就可以了。感谢退出macroexpand
,确切了解它为什么需要额外的参数才能工作。。。这是有趣的东西:)安克尔:会的!再次感谢。这不是一个错误吗?使用api不需要了解实现细节。@andrew:这不是典型意义上的api,->
是一个宏,宏以“代码作为数据”工作,因此基本上宏需要处理的情况数量会变得很大,因为您可以将任何s表达式传递给它。在这种情况下,宏不会处理这种特殊情况。可能会重复伟大的深思熟虑!这可以归结为次优(草率?)语言设计
(-> 4 (+ 1) (- 1) (+ 1))