8

我正在读一本关于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.

那么这如何适应呢?

4

3 回答 3

10

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 在这里用词不当,因为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   

当参数的数量是可变的时,我只在实践中使用部分。否则我个人偏好使用匿名函数阅读器表单#( ... )

于 2013-04-13T00:27:16.947 回答
6

partial实际上并没有检查它的第一个参数支持哪些arities;一个可以说更准确的文档字符串会说它“接受一个函数 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)

于 2013-04-13T00:27:24.517 回答
0

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

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

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

于 2019-01-15T08:34:00.300 回答