如何评估 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" 的列表)。你有功能,没有形式。
你 map
和 apply
,但是 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
!
我的问题与这个问题非常相似: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:
而不是 evaluser=> (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" 的列表)。你有功能,没有形式。
你 map
和 apply
,但是 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
!