Clojure部分应用解释

9

我正在阅读一本关于Clojure的书,遇到了一个例子,但我并不完全理解。

这是REPL中的代码:

user=> (repeatedly 10 (rand-int 10))
ClassCastException java.lang.Integer cannot be cast to clojure.lang.IFn  clojure.core/repeatedly/fn--4705 (core.clj:4642)

user=> (repeatedly 10 (partial rand-int 10))
(5 0 5 5 2 4 8 8 0 0)

我的问题是:为什么在这里需要使用partial,它如何适用于partial的定义、repeatedly的定义和语法。部分...

Takes a function f and fewer than the normal arguments to f, and
  returns a fn that takes a variable number of additional args. When
  called, the returned function calls f with args + additional args.

那么这与什么有关呢?

哈哈,我也是从braveclojure.com来到这里的。 - JoeSchr
3个回答

11

Partial只是一种更简单的定义匿名函数的方式,它固定了某些参数并将剩余参数传递给创建的函数。

在这种情况下

user> (repeatedly 10 (partial rand-int 10))
(3 1 3 6 1 2 7 1 5 3)

等同于:

user> (repeatedly 10 #(rand-int 10))                        
(9 5 6 0 0 5 7 6 9 6)

在这里,“partial”是一个误称,因为它被用于提前确定rand-int的所有参数(或者说唯一的一个参数)。

更有趣的应用可以更好地说明partial的功能:

(partial + 4)

产生相当于:

(fn [& unfixed-args] (apply + (concat [4] unfixed-args)))

(它并不是字面上产生这个结果)它的思想是构建一个函数,将不定参数与固定参数结合起来,并使用足够的参数调用你传递给partial的函数,以便它能正常工作。

user> ((fn [& unfixed-args] (apply + (concat [4] unfixed-args))) 5 6 7 8 9)       
39
user> ((partial + 4) 5 6 7 8 9)
39   

在实践中,当参数数量可变时,我只会使用 partial。否则,我更喜欢使用匿名函数读取器形式 #( ... )


是的,我认为那将是更符合语义的解决方案。谢谢。 - tonino.j

7

partial实际上不会检查它的第一个参数支持哪些参数数量; 一个更准确的文档字符串可能会说它“接受一个函数f和一些传递给f的参数”。(显然,如果你提供过多的参数,生成的部分应用函数将会出错,但只有在尝试调用它时才能观察到这一点。)因此,(partial rand-int 10)是可以的,即使提供给rand-int的参数数量不是“比正常情况下少”。

要使用partial或类似#(rand-int 10)的东西的原因是repeatedly期望其最后一个参数是一个它可以重复调用的函数,而(rand-int 10)将是一个数字。

与此相比,repeat返回一个包含指定项重复指定次数(或在一元情况下无限次)的序列。在这里,(rand-int 10)将是一个合适的第二个参数,但当然它将是某个特定的数字,所以结果看起来像(8 8 8 8 8 ...); repeatedly将为返回的序列的每个项单独调用(partial rand-int 10),因此您将从中获得一个序列(可能不同且独立)的随机数。


我想到问题可能与(rand-int 10)返回一个数字有关.. #()从语义上看肯定是更好的解决方案 - tonino.j

0

我们感兴趣的是(repeatedly number function)的签名。

在这种情况下,partial 只是将 rand-int 10 包装成一个函数,可以被外部函数 repeatedly 返回和使用。

没有 partial(或 #),内部表达式会在外部表达式之前解析(有例外,但现在让我们保持简单),所以当没有 partial 调用 repeatedly 时,传递给它的将是 rand-int 的返回值,即一个 Int 类型而不是一个函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接