如何评估 Clojure 中的纯函数序列

How to evaluate sequence of pure functions in Clojure

我的问题与这个问题非常相似:How to evaluate a sequence of impure functions in Clojure? 但是我如何计算纯函数的序列并获得另一个序列的结果而不是不纯函数?

假设我们有一个函数向量,例如:

[#(str "a" "b") #(str "c" "d") #(str "e" "f")]

我们需要这样的输出:

("ab" "cd" "ef")

我试过类似的东西:

(map eval [#(str "a" "b") #(str "c" "d") #(str "e" "f")])

但它只是 returns 一个函数引用向量。

您可以在 map 中使用 (fn [f] (f))#(%)

有多种方法可以满足您的要求。这取决于你是否想要一个 lazy 序列或不(你可能想要 lazy ,因为没有副作用,但如果你想要一个密集的计算,你可能想要 no-lazy缓存),或者如果你想要一个向量作为输出(与你的输入相同)。我会尝试按照您的尝试去做。

您的地图与 eval 正在对每个 fn 执行以下操作:

user=> (eval #(str 1))
#<user$eval1332$fn__1333 user$eval1332$fn__1333@38747597>

但是您想要如下内容:

user=> (eval (#(str 1)))
"1"

您希望 eval 应用 fn,即:fn 应该是列表的第一个元素。让我们把它放在一个列表中:

user=> (map (comp eval list) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")

酷。但是您可能想使用 apply:

而不是 eval
user=> (apply #(str 1))
; ArityException Wrong number of args (1)

加油!它失败了。 apply 没有 0 元重载,但我们可以传递一个空列表:

user=> (apply #(str 1) ())
"1"

好多了。让我们用地图来做:

user=> (map #(apply % ()) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")

或者更好的是,如果你的函数不接收任何参数,你最好按照@Magos 的建议去做:

user=> (map #(%) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])                                                                              
("ab" "cd" "ef")

eval 评估 Clojure 表单(即包含 "code" 的列表)。你有功能,没有形式。

mapapply,但是 apply 接受一个函数和一个 seq 参数。由于你没有参数,你可以使用空向量:

(map apply
     [#(str "a" "b") #(str "c" "d") #(str "e" "f")]
     (repeat []))

但是如果你使用 for:

会更短更清楚
(for [f [#(str "a" "b") #(str "c" "d") #(str "e" "f")]]
  (f))

备注

作为 eval 计算 clojure form

(eval '(+ 1 1)) ;=> 2

它对函数有什么作用? 没有!eval 将函数视为文字:

((eval +) 1 1) ;=> 2

对于你的情况:

(def stuff [#(str "a" "b") #(str "c" "d") #(str "e" "f")])

...我们有

(= stuff (map eval stuff)) ;=> true

虽然

(= [#(str "a" "b") #(str "c" "d") #(str "e" "f")]
   (map eval [#(str "a" "b") #(str "c" "d") #(str "e" "f")]))
;=> false

... 因为对应的函数是不同的对象,虽然在操作上是相同的。

这就是为什么 eval 对你没用。所以关注

也许值得一看 pcalls and/or pvalues

(pcalls #(str "a" "b") #(str "c" "d") #(str "e" "f"))
;=> ("ab" "cd" "ef")

请注意pcalls里面使用的是future