可以使用Clojure / Lisp宏来实现这种lambda语法吗?

时间:2012-09-04 19:20:51

标签: syntax clojure macros lambda nested-function

((#(%a %b') {a:1 b:2}) {a:3 b:4}) -> (1 4)

在JavaScript中将与:

相同
(function(x){ return function(y){ return [x.a,y.b]; }})({a:1,b:2})({a:3,b:4});
Output: [1,4]

因此,换句话说,lambdas的一个简短语法(与Clojure的当前实现不同)允许嵌套函数。

3 个答案:

答案 0 :(得分:4)

如果您只想使用直接的Clojure代码而不使用任何宏(即相当于JavaScript版本),那么您只需要:

(((fn [x] (fn [y] (list (:a x) (:b y)))) {:a 1 :b 2}) {:a 3 :b 4}) 
=> (1 4)

您还可以使用宏来执行此操作,前提是您为实际的宏标识符选择#()以外的其他格式,例如:你可以这样做:

(((my-lambda %a %b) {:a 1 :b 2}) {:a 3 :b 4}) 
=> (1 4)

(p.s。我修复了orginival问题中的地图关键字,a:1将不起作用.....)

方法是:

  • 创建一个名为my-lambda
  • 的宏
  • 让此宏检查传递的符号,并将其转换为针对自动生成的符号的关键字查找
  • 使用自动生成的符号输出函数代码,例如:(fn [sym1] (fn [sym2](list (:a sym1) (:b sym2))))

这种方法可以很好地与嵌套函数一起使用。用Clojure lambdas知道的重要事情是(fn [...] ...)可以嵌套,但#(...)不能嵌套(因为否则会导致函数参数模糊)。

您无法直接覆盖#()语法,因为Clojure尚不支持读取器宏。我实际上认为这是一件好事 - 允许任意重新定义语法可能会导致一些人编写相当难以维护的代码而没有明显的好处(保存一些字符的输入但是可读性/代码理解能力降低

我想在Clojure代码中我看到#()的任何地方我知道它是一个常规的匿名函数,而不必担心有人重新定义它以做一些奇怪的事情。

答案 1 :(得分:2)

匿名阅读器宏#( )语法不允许嵌套匿名函数,因为不清楚给定参数%2将对应哪个函数。人们已经提出了解决邮件列表中模糊性的方法,并且一致认为(fn [arg] ...)形式足够短且足够清晰,可以在大多数情况下使用;嵌套%2分辨率在某些情况下可能不够清晰或简洁。

(function(x){ return function(y){ return [x.a,y.b]; }})

可以写成

(fn [x] (fn [y] [(.x a) (.y b)]))

添加您自己的允许嵌套函数的读取器宏会很困难,因为Clojure故意不支持用户定义的读取器宏。

答案 2 :(得分:0)

对于Clojure 1.4,Clojure 支持支持用户定义的读取器宏,您可以使用它来定义自己的lambda语法。但是,它们不允许您劫持#()语法。获取详细信息here