Clojure';s funcs don';通过列表发送时,似乎无法按预期工作

Clojure';s funcs don';通过列表发送时,似乎无法按预期工作,clojure,Clojure,在Clojure REPL中,这个表达式 ( #(for [x %] (+ 100 (second x))) ['(+ 38) '(+ 48)] ) 按预期生产(138 148台) 但是这个 ( #(for [x %] ((first x) 100 (second x))) ['(+ 38) '(+ 48)] ) 生产(38 48),这似乎真的很奇怪 两个表达式真的应该产生相同的结果! 我错过了什么? 我会很感激任何能解开这个谜团的想法 顺便说一句,我尝试使用“apply(firstx)”

在Clojure REPL中,这个表达式

( #(for [x %] (+ 100 (second x)))  ['(+ 38) '(+ 48)] )
按预期生产(138 148台)

但是这个

( #(for [x %] ((first x) 100 (second x))) ['(+ 38) '(+ 48)] )
生产(38 48),这似乎真的很奇怪

两个表达式真的应该产生相同的结果! 我错过了什么? 我会很感激任何能解开这个谜团的想法

顺便说一句,我尝试使用“apply(firstx)”并将其余参数打包到一个列表中,但这似乎并不重要。同样意想不到的结果又回来了

另外,为了验证+确实从输入中得到解析,我将以下内容提供给REPL

( #(for [x %] (resolve (first x) )) '((+ 38) (+ 48)) )
产生

 (#'clojure.core/+ #'clojure.core/+)   as expected.
在这种情况下,
+
是一个符号,而不是一个函数,因为它已在列表中引用。但是,符号被定义为在作为函数调用时进行地图查找(与关键字相同)。所以
('+10038)
(get 100'+38)
相同。最后一个论点是“如果你在地图上找不到我想要的东西,就把它还给我”。由于
100
不是映射,
+
使用该参数作为返回值

要让它实现您想要的功能,您有两个选择:

  • 使用向量而不是带引号的列表可以确保
    +
    得到适当的解析

    ( #(for [x %] ((first x) 100 (second x))) [[+ 38] [+ 48]] )
    
  • 自行解决此问题,以确保使用
    +
    函数而不是
    +
    符号

    ( #(for [x %] ((resolve (first x)) 100 (second x))) ['(+ 38) '(+ 48)] )
    

  • 当您引用列表时,如
    ”(+38)
    ,列表中的任何项目都不会被计算。因此,
    +
    只是一个符号,而不是对clojure.core中加法函数的引用

    将此符号作为函数调用的结果有点混乱,特别是因为您恰好使用两个参数调用它。@mange已经解释了原因:将符号作为函数调用会尝试在第一个参数中查找符号,当查找失败时,将(可选)第二个参数作为默认参数返回:

    ('x)       ; throws ArityException
    ('x 1)     ;=> nil
    ('x 1 2)   ;=> 2
    ('x 1 2 3) ; throws ArityException
    
    您有几个选择:

  • 使用矢量而不是带引号的列表:
    [+38]
    。向量的所有元素都会被计算(如在一个不带引号的列表中),但向量只是一个数据结构,而不是函数调用的语法(如列表)
  • 使用
    resolve
    函数查找符号引用的函数。请注意,
    resolve
    在当前名称空间中查找符号。因此,如果引用列表的构造和函数的调用发生在不同的名称空间中,这可能会导致令人惊讶的结果(如果您恰好在不同的名称空间中对同一符号有两个不同的定义)
  • 在列表中使用语法引号而不是简单的引号,并取消对符号的引号(计算):
    `(~+38)

  • +1.详细说明。由于问题实际上是在引用中,所以您实际上不需要更改数据结构,列表也可以工作。您只需删除文字形式,然后使用例如
    (list+38)
    谢谢您的精彩回答。我用作输入的列表列表是使用分区生成的,所以我更喜欢使用这种形式的输入本身。在我发布这个问题时,我确实转换成了向量,因为我注意到它生成了求值的func(REPL使用#^来显示它),但是解析(第一个x)的工作让我困惑,因为我预期(第一个x)调用会产生错误,但事实并非如此。(get 100'+38)帮助我解开了这一谜团。感谢您的深刻见解,尤其是语法引用示例。我用作输入的列表列表是使用分区生成的。在我发布这个问题时,我确实转换成了向量,因为我注意到它生成了求值的func(REPL使用#^来显示它),但是解析(第一个x)的工作让我困惑,因为我预期(第一个x)调用会产生错误,但事实并非如此。曼奇和你的回答帮我解决了这个问题。
    ('x)       ; throws ArityException
    ('x 1)     ;=> nil
    ('x 1 2)   ;=> 2
    ('x 1 2 3) ; throws ArityException