【问题标题】:clojure partial clarificationclojure 部分澄清
【发布时间】:2013-04-13 00:19:54
【问题描述】:

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

那么这如何适应?

【问题讨论】:

    标签: clojure functional-programming jvm read-eval-print-loop


    【解决方案1】:

    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   
    

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

    【讨论】:

    • 是的,我认为这在语义上是更合适的解决方案。谢谢
    【解决方案2】:

    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),因此您将从中获得一个(可能不同的、独立的)随机数序列。

    【讨论】:

    • 我认为问题在于 (rand-int 10) 返回一个数字。#() 从语义上来说绝对是一个更好的解决方案
    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-22
      • 1970-01-01
      • 2016-01-24
      • 2019-11-15
      • 2013-06-05
      • 2013-07-30
      • 1970-01-01
      相关资源
      最近更新 更多