mik*_*era 8 lisp functional-programming clojure
我有时发现在Clojure中定义简化的arity版本的函数很方便,这些函数返回一个部分函数,例如
(defn prefix
([pre string]
(str pre ":" string))
([pre]
(fn [string]
(prefix pre string))))
Run Code Online (Sandbox Code Playgroud)
这意味着您可以执行以下任一操作:
(prefix "foo" 78979)
=> "foo:78979"
((prefix "foo") 78979)
=> "foo:78979"
Run Code Online (Sandbox Code Playgroud)
这看起来很Haskell-ish并且避免了partial创建部分函数的需要.
但它在Lisp中被认为是良好的编码风格/ API设计吗?
使用partial创造咖喱功能是基于概念明确越好(在大多数情况下:)).我发现这个概念在Clojure,Python等动态类型语言中更适用/使用可能是因为缺少类型签名/静态类型,使事情更明确.
在默认情况下函数被调用的语言中,函数调用也是curry.当一个人写作时(f a b c),语言将
其解释为(((f a) b) c).在Clojure中并非如此.
我相信在默认情况下不调用调用的环境中创建curried函数会产生概念上的不匹配 - 这种结构可能会引起读者混淆(我的意思是代码的人类读者).
如果你的函数有超过2个参数,那么定义会很快变得难看.假设一个函数有4个参数.要完全模拟currying调用,你需要处理一些情况,例如((f a b) c d)当有人第一次传递2个参数然后传递其余两个参数时.在这种情况下,双参数函数的重载版本需要返回一个重载函数,该函数的行为会有所不同,具体取决于它是获得1还是2个参数.我想有可能用宏来自动化,但仍然如此.
此外,你杀死了定义默认参数和& rest构造的可能性.
嗯......就个人而言,我宁愿看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"
Run Code Online (Sandbox Code Playgroud)