8

我有时发现在 Clojure 中定义返回部分函数的简化的 arity 版本的函数很方便,例如

(defn prefix 
  ([pre string] 
    (str pre ":" string))

  ([pre] 
    (fn [string]
      (prefix pre string)))) 

这意味着您可以执行以下任一操作:

(prefix "foo" 78979)
=> "foo:78979"

((prefix "foo") 78979)
=> "foo:78979"

这看起来很像 Haskell 并且避免了partial创建部分函数的需要。

但它是否被认为是 Lisp 中良好的编码风格/API 设计?

4

3 回答 3

9

用于创建柯里partial化函数基于Explicit 的概念更好(在大多数情况下:))。而且我发现这个概念在动态类型语言(如 Clojure、Python 等)中更适用/使用,可能是因为缺少类型签名/静态类型,让事情变得明确更有意义。

于 2012-05-21T04:04:02.963 回答
7

在默认情况下对函数进行柯里化的语言中,函数调用也会被柯里化。当一个人写作 (f a b c)时,语言将其解释为(((f a) b) c). 在 Clojure 中并非如此。

我相信在默认情况下调用不进行柯里化的环境中制作柯里化函数会产生概念上的不匹配——这种结构可能会导致读者混淆(我的意思是人类读者的代码。)

如果你的函数有超过 2 个参数,定义很快就会变得丑陋。假设一个函数有 4 个参数。要完全模拟柯里化调用,您需要处理一些情况,例如((f a b) c d)有人先传递 2 个参数,然后传递其余两个参数。在这种情况下,双参数函数的重载版本需要返回一个重载函数,该函数的行为取决于它是获取 1 个参数还是 2 个参数。我想有可能用宏来自动化,但仍然如此。

此外,您消除了定义默认参数和& rest构造的可能性。

于 2012-05-21T08:45:06.113 回答
6

嗯......就个人而言,我宁愿看到partial,因为这清楚地说明了发生了什么。

我不知道它是“好”还是“坏”的编码风格,但我以前从未在现有的 Clojure 代码中看到过这种风格,我可以想象使用 API 的人会期望两者(prefix "foo" 78979)(prefix "foo")返回相同类型的对象.

为了使两个功能之间的区别清晰,您可以执行以下操作:

(defn prefix [pre string]
  (str pre ":" string))

(defn prefix-fn [pre]
  (fn [string]
    (prefix pre string)))

(prefix "foo" 78979)      ; => "foo:78979"
((prefix-fn "foo") 78979) ; => "foo:78979"
于 2012-05-21T02:28:05.397 回答