在Clojure REPL中,这个表达
( #(for [x %] (+ 100 (second x))) ['(+ 38) '(+ 48)] )
按预期产生(138 148)
但是这个
( #(for [x %] ((first x) 100 (second x))) ['(+ 38) '(+ 48)] )
产生(38 48),这似乎真的很奇怪。
这两个表达式确实应该产生相同的结果! 我错过了什么? 将会欣赏任何解决这个谜团的想法。
顺便说一句,我尝试使用'apply(first x)'并将其余的args打包成一个列表,但似乎并不重要。同样出人意料的结果又回来了。另外,为了验证+确实从输入中解析了+,我将以下内容提供给REPL
( #(for [x %] (resolve (first x) )) '((+ 38) (+ 48)) )
产生了
(#'clojure.core/+ #'clojure.core/+) as expected.
答案 0 :(得分:10)
( #(for [x %] ((first x) 100 (second x))) ['(+ 38) '(+ 48)] )
在此,+
是一个符号,而不是一个函数,因为它已在列表中引用。但是,符号被定义为在作为函数调用时进行映射查找(与关键字相同)。因此('+ 100 38)
与(get 100 '+ 38)
相同。最后一个论点是“如果你在地图中找不到我想要的东西,那就回归”。由于100
不是地图,+
使用该参数作为返回值。
要让它做你想做的事,你有两个选择:
使用向量而不是引用列表可确保+
得到适当解析。
( #(for [x %] ((first x) 100 (second x))) [[+ 38] [+ 48]] )
自行解决,以确保您使用+
函数而不是+
符号。
( #(for [x %] ((resolve (first x)) 100 (second x))) ['(+ 38) '(+ 48)] )
答案 1 :(得分:3)
当您引用列表时,例如'(+ 38)
,列表中的所有项都不会被评估。因此+
只是一个符号,而不是对clojure.core中的加法函数的引用。
将此符号作为函数调用的结果有点令人困惑,特别是因为您碰巧使用两个参数调用它。原因已由@mange解释:调用符号作为函数尝试在第一个参数中查找符号,在查找失败时将(可选)第二个参数作为默认值返回:
('x) ; throws ArityException
('x 1) ;=> nil
('x 1 2) ;=> 2
('x 1 2 3) ; throws ArityException
您有几种选择:
[+ 38]
。评估向量的所有元素(如在不带引号的列表中),但向量只是一个数据结构,而不是列表中函数调用的语法。resolve
功能查找符号引用的功能。请注意resolve
在当前命名空间中查找符号。因此,如果引用列表的构造和函数的调用发生在不同的名称空间中,这可能会导致令人惊讶的结果(如果您碰巧对不同名称空间中的相同符号有两个不同的定义)。`(~+ 38)