我正在阅读The Joy of Clojure,在有关paralellization的部分中,解释了函数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有这两个相似的功能。有什么可以用一个而不是另一个吗?一些人为的例子可能会有所帮助。
答案 0 :(得分:6)
pvalues是一个围绕pcalls的方便宏,但因为宏不是第一类它不能以与函数相同的方式组合或传递。这是一个只有pcalls工作的例子:
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时,重要的是不要限制用户只通过宏与您的库进行交互,因为它们会受到诸如此类的限制。