4

许多 Clo​​jure 函数接受不同数量的参数,我经常对文档以及它与我应该使用函数的方式之间的关系感到有些困惑。

例如(doc partial)返回这个:

([f arg1] [f arg1 arg2] [f arg1 arg2 arg3] [f arg1 arg2 arg3 & more])

我的问题不是专门针对部分问题,而是...

为什么最多arg1 arg2 arg3 & more而不是arg1 & morearg1 arg2 & morearg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 & more

我对最后一个很有趣,但这是一个非常现实的问题:是什么决定了需要在& more之前放置多少个“argX” ?

4

2 回答 2

7

以下答案是我的猜测:看看partialshow us 的实现:

(defn partial
  "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."
  {:added "1.0"
   :static true}
  ([f arg1]
   (fn [& args] (apply f arg1 args)))
  ([f arg1 arg2]
   (fn [& args] (apply f arg1 arg2 args)))
  ([f arg1 arg2 arg3]
   (fn [& args] (apply f arg1 arg2 arg3 args)))
  ([f arg1 arg2 arg3 & more]
   (fn [& args] (apply f arg1 arg2 arg3 (concat more args)))))

如您所见,对 partial 的每次调用都在做同样的事情 - 即返回一个接受一些 argsapply的函数,并使用输入 args 和新 args 调用输入函数。所以这确实可以写成arg1 & more。但是等等,让我们看看 apply 的实现:

(defn apply
 "Applies fn f to the argument list formed by prepending intervening arguments to args."
 {:added "1.0"
  :static true}
 ([^clojure.lang.IFn f args]
    (. f (applyTo (seq args))))
 ([^clojure.lang.IFn f x args]
    (. f (applyTo (list* x args))))
 ([^clojure.lang.IFn f x y args]
    (. f (applyTo (list* x y args))))
 ([^clojure.lang.IFn f x y z args]
    (. f (applyTo (list* x y z args))))
 ([^clojure.lang.IFn f a b c d & args]
    (. f (applyTo (cons a (cons b (cons c (cons d (spread args)))))))))

Apply 是一个核心函数,当给定不同数量的参数时,它的执行方式也不同。这是出于性能原因应用的优化。这就是暴露不同部分(和其他此类函数)的原因,因为不同的部分代码的内部执行是不同的。

我假设 clojure/core 团队认为暴露部分超出 arg1 arg2 arg3 及更多(即编写 arg1 arg2 arg3 arg4 及更多)的数量并不美观,因此他们决定停止在 3 个 args 及更多。

于 2012-05-26T19:33:41.103 回答
3

你认为什么都是合理的。如果函数不是可变的,那么调用函数会更快,因此它们提供了几个如果您不超过其限制将直接调用的函数。

我认为函数的 IFn 也有 20(?) args 的限制,但我不知道编译器中是否有解决方法。

于 2012-05-26T19:37:22.573 回答