将函数组合为 clojure 中高级函数的可选参数

composing functions as optional arguments to higher-level function in clojure

我正在尝试在 Clojure 中创建一个多参数函数,如果给定一个向量参数,只需将另一个函数应用于该向量;如果给定一个向量加上 1 个或多个函数,则将这些函数的组合映射到向量上,然后应用第三个函数。但不知何故,我似乎无法访问第一个之外的任何可选参数。

玩具示例代码:

(defn times2 [num] (* 2 num))
(defn square [num] (* num num))
(defn plusfiveall [vec-of-nums] (map #(+ 5 %) vec-of-nums))
(defn toynums
  ([vec-of-nums] 
   (plusfiveall vec-of-nums))
  ([vec-of-nums & [funcs]]
   (let [moremath (comp funcs)]
      (plusfiveall (map moremath vec-of-nums)))))

我认为应该发生的事情:

(toynums [1 2 3]) = (6 7 8)

(toynums [1 2 3] times2) = (7 9 11)

(toynums [1 2 3] times2 square) = (7 13 23)

但是虽然前两个示例按预期工作,但第三个示例无法应用 square:相反,我得到 (toynums [1 2 3] times2 square) --> (7 9 11)

为了深入研究这个问题,我也尝试了一个没有映射的版本,并且有同样令人惊讶的行为:

(defn comp-nomap 
  ([num] (plusfive num))
  ([num & [funcs]] 
   (let [funmath (comp funcs)] 
     (plusfive (funmath num)))))

(comp-nomap 3) = 8 符合预期

(comp-nomap 3 times2) = 11 符合预期

(comp-nomap 3 times2 square) 也 = 11,而不是应有的 23。

求助?谢谢!

这个结构产生了预期的答案:

(defn toynums
  ([vec-of-nums]
   (plusfiveall vec-of-nums))
  ([vec-of-nums & funcs]
   (let [moremath (apply comp funcs)]
     (plusfiveall (map moremath vec-of-nums)))))

&之后的参数会自动收集到一个序列中,这样里面就可以使用apply,这样就可以让comp函数拥有序列的内容作为参数传递给它。所以你真的做对了,只是错过了一件事。您需要查找 'varadic' 个参数。

你的第二个参数使用可变参数的解构,它总是从提供的参数中提取第一个函数。您还需要 apply comp 对序列中的参数起作用:

(defn comp-nomap
  ([num] (plusfive num))
  ([num & funcs]
    (let [funmath (apply comp funcs)]
      (plusfive (funmath num)))))