我正在阅读The Joy of Clojure,在关于并行化的部分中,对pvalues
,pmap
和pcalls
函数进行了解释,并简要说明了每个函数的用法。以下是pvalues
和pcalls
给出的示例:
(defn sleeper [s thing] (Thread/sleep (* 1000 s)) thing)
(pvalues
(sleeper 2 :1st)
(sleeper 3 :2nd)
(keyword "3rd"))
(pcalls
#(sleeper 2 :1st)
#(sleeper 3 :2nd)
#(keyword "3rd"))
我了解两者之间的技术差异-
pvalues
接受可变数量的“值”进行计算,而pcalls
接受“任意数量的不带参数的函数”,以并行方式进行调用。在这两种情况下,都将返回结果的惰性序列。我的问题本质上是,您何时会使用一个与另一个?似乎唯一的语义差异是,您将
#
粘贴到pcalls
的每个参数之前,将其转换为匿名函数。因此,仅从保存击键和使用更简单的代码的角度来看,仅使用pvalues
会更有意义吗? -如果是的话,为什么还要有pcalls
函数呢?我用
pcalls
可以理解,可以用一个符号代替一个函数,但是如果您想在pvalues
中使用这样的函数,您可以将函数放在括号中以便对其进行调用。我对为什么Clojure的这两个功能如此相似感到有些困惑。您可以对其中一项进行任何操作,而对另一项则无能为力?一些人为的例子可能会有所帮助。
最佳答案
pvalues是pcall周围的便捷宏,尽管因为宏不是一流的,所以它不能以函数可以的相同方式组成或传递。这是仅pcall起作用的示例:
user> (defn sleeper [s thing] (Thread/sleep (* 1000 s)) thing)
#'user/sleeper
user> (def actions [#(sleeper 2 :1st) #(sleeper 3 :2nd) #(keyword "3rd")])
#'user/actions
user> (apply pcalls actions)
(:1st :2nd :3rd)
user> (apply pvalues actions)
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/pvalues, compiling:(NO_SOURCE_PATH:1:1)
在Clojure中设计API时,请不要限制用户仅通过宏与您的库进行交互,这一点很重要,因为那样一来,他们就会陷入诸如此类的限制中。