我正在阅读The Joy of Clojure,在关于并行化的部分中,对pvaluespmappcalls函数进行了解释,并简要说明了每个函数的用法。以下是pvaluespcalls给出的示例:

(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时,请不要限制用户仅通过宏与您的库进行交互,这一点很重要,因为那样一来,他们就会陷入诸如此类的限制中。

09-30 20:07