2011-09-21 86 views
3

我正在研究koan的解决方案。我难以理解为什么我的解决方案不起作用,但使用comp的定义确实有效。当我看的comp的定义,我看到:函数组合失败

(defn comp 
    "Takes a set of functions and returns a fn that is the composition 
    of those fns. The returned fn takes a variable number of args, 
    applies the rightmost of fns to the args, the next 
    fn (right-to-left) to the result, etc." 
    {:added "1.0"} 
    ([f] f) 
    ([f g] 
    (fn 
     ([] (f (g))) 
     ([x] (f (g x))) 
     ([x y] (f (g x y))) 
     ([x y z] (f (g x y z))) 
     ([x y z & args] (f (apply g x y z args))))) 
    ([f g h] 
    (fn 
     ([] (f (g (h)))) 
     ([x] (f (g (h x)))) 
     ([x y] (f (g (h x y)))) 
     ([x y z] (f (g (h x y z)))) 
     ([x y z & args] (f (g (apply h x y z args)))))) 
    ([f1 f2 f3 & fs] 
    (let [fs (reverse (list* f1 f2 f3 fs))] 
     (fn [& args] 
     (loop [ret (apply (first fs) args) fs (next fs)] 
      (if fs 
      (recur ((first fs) ret) (next fs)) 
      ret)))))) 

而我的解决方案很相似:

(defn mycomp 
    ([f] f) 
    ([f1 f2] 
     (fn 
     ([] (f1 (f2))) 
     ([a] (f1 (f2 a))) 
     ([a & more] (f1 (apply f2 a more))) 
     ) 
    ) 
    ([f1 f2 & fs] 
     (let [fxns (reverse (list f1 f2 fs))] 
      (fn [& args] 
     (loop [ret (apply (first fxns) args) fxns (next fxns)] 
      (if fxns 
      (recur ((first fxns) ret) (next fxns)) 
      ret)))))) 

两个,从我可以告诉之间最大的区别,是第一定义包括三个或更多功能,而第二个定义组成两个或更多个功能

请指出我的定义有什么不正确。

回答

8

(list f1 f2 fs)看起来可能是嫌犯 - 前两个是函数,最后一个是函数列表,所以你创建一个包含多个对象类型的列表,然后统一处理它们。您可以使用list*来解决该问题。

但是,作为一个更广泛的观点:不要试图做“两个或两个以上”的功能,只做零或更多!没有特殊情况意味着更少的代码; clojure.core只有一堆展开速度的例子。如果你的骨骼是(fn [& fs] (fn [& args] ...)),你的生活就容易多了。

+0

感谢您指出'list *'的东西,我不明白'list'和'list *'之间有区别。另外,我使用零个或多个参数重新实现了我的解决方案,这使得代码更易于理解。再次感谢! – Davidann