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

时间:2016-03-05 17:44:23

标签: clojure composition

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

玩具示例代码:

(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应该是。

帮助?谢谢!

2 个答案:

答案 0 :(得分:2)

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

(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'你需要查询的论据。

答案 1 :(得分:2)

你的第二个arity使用varargs的解构,它总是从提供的函数中提取第一个函数。您还需要apply comp函数来处理序列中的参数:

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