Lambda 线程宏->;使用匿名函数

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

我知道Clojure中的`->theadeding宏将提供的所有函数应用于给定的参数。但是,它似乎不适用于匿名函数。例如:

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))