2
((#(%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 当前的实现)允许嵌套函数。

4

3 回答 3

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)

(ps我修复了原始问题中的地图关键字,a:1不起作用.....)

方法是:

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

这种方法对嵌套函数非常有效。Clojure lambdas 要知道的重要一点是它 (fn [...] ...)可以嵌套,但不能嵌套#(...)(否则会导致函数参数的歧义)。

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

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

于 2012-09-05T03:00:05.043 回答
2

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

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

可以写成

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

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

于 2012-09-04T20:50:06.613 回答
0

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

于 2013-05-25T04:55:39.343 回答