【问题标题】:why (map (fn [f] (f 0)) `(inc)) returns (nil) in Clojure为什么 (map (fn [f] (f 0)) `(inc)) 在 Clojure 中返回 (nil)
【发布时间】:2021-11-11 08:37:49
【问题描述】:
uesr=> (defn ff [f] (f 0))
uesr=> (ff inc)
1
uesr=> (map ff `(inc))
(nil)

为什么ff地图中表现不佳?

【问题讨论】:

  • 也许你已经知道了,但考虑到我认为你想要的用例,即在同一个参数上运行多个函数可以使用juxt 高阶函数:((juxt inc dec (fn [x] (* 2 x))) 1) => [2 0 2] 来实现。它接受一个函数列表并返回一个函数,该函数以向量的形式返回使用给定 arg 调用每个函数的结果

标签: clojure


【解决方案1】:

看看传入map的内容:

(map #(println %1) '(inc))
inc
=> (nil)

(map #(println %1) `(inc))
clojure.core/inc
=> (nil)

inc 都在引号内,因此它们的计算结果无法正常工作。在第二个示例中,使用了syntax quote,因此inc 解析为完全限定符号。

现在你的代码:

(defn ff [f] (f 0))

(map ff `(inc))
=> nil

您的函数计算结果为:

('inc 0)
=> nil

('clojure.core/inc 0)
=> nil

符号在对象中查找自己:

('inc {'inc 1 'dec 2})
=> 1
('inc #{'inc 'dec})
=> inc

0 中没有找到'inc,因此返回了nil(您甚至可以添加 not-found 参数)。

('inc 0)
=> nil

('inc 0 1)
=> 1

要获得您想要的结果,请使用list 或向量:

(map #(println %1) [inc])
#object[clojure.core$inc 0x4fa1f07 clojure.core$inc@4fa1f07]
=> (nil)

(map #(%1 0) (list inc))
=> (1)

(map #(%1 0) [inc])
=> (1)

【讨论】:

    【解决方案2】:

    问题是子表达式

    `(inc)
    

    它评估为带有单个符号 inc 的列表:

    `(inc)
    ;; => (clojure.core/inc)
    

    因为反引号阻止了对引号后表达式的求值。如果你这样做会更明显

    (map class `(inc))
    ;; => (clojure.lang.Symbol)
    
    (every? fn? `(inc))
    ;; => false
    

    如果您改为使用 向量字面量list 函数来构造包含 inc 函数作为其单个元素的序列,您将看到它将评估为一个函数:

    (map class [inc])
    ;; => (clojure.core$inc)
    
    (every? fn? [inc])
    ;; => true
    
    (map class (list inc))
    ;; => (clojure.core$inc)
    
    (every? fn? (list inc))
    ;; => true
    

    以下代码将完成您想要的:

    (map ff [inc])
    ;; => (1)
    

    【讨论】:

      【解决方案3】:

      就像之前的回答者已经回答了一样 - 只是解释一下:

      quote/'backquote/``` 用于构造列表与list 用于构造列表不同,因为list 在构造列表时评估其每个元素 - 而@ 987654326@ 或 backquote 不要。它们会生成一个初步未评估的符号列表。

      所以'(inc) 生成一个包含符号inc 的列表,而(list inc) 生成一个包含符号inc 后面的函数的列表——实际的inc 函数。

      【讨论】:

        【解决方案4】:

        诀窍是您希望将 inc 解析为 var(绑定到递增的函数)。

        如果您避免引用(例如,通过使用矢量文字或 list 函数),则解决方法自然会发生:

        (map (fn [f] (f 0)) [inc])
        (1)
        
        (map (fn [f] (f 0)) (list inc))
        (1)
        

        但是您的问题是关于文字列表。引用禁止 var 解析。因此,您通过使用语法引号(与普通引号相反,撇号)走在正确的轨道上,因为您可以取消引用语法引号中的 s 表达式:

        (map (fn [f] (f 0)) `(~inc))
        (1)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-08-10
          • 1970-01-01
          • 2017-11-25
          • 1970-01-01
          • 1970-01-01
          • 2020-02-29
          • 2020-02-08
          相关资源
          最近更新 更多