这一章是本书最重要的地方,前几章,基本一天能看一章,这一章看了一个礼拜。你也许听过 Paul Graham 的 天使投资公司,Ycombinator - 这一章我们不仅仅解释 YCombinator 并在 Clojure中实现它。
首先,神马是 YCombinator 理论?The YCombinator is a way to do recursion in a language that doesn’t support recursion. Instead recursion is defined as a set of rewrite rules. 也就是说他是一章方法,可以在不支持递归的语言里面使用递归。用一系列重写规则代替递归。
不是吧,就我所知不支持递归的语言要追溯到60年代了。现在再说这个还有神马意义马?其实,仅仅为了上面的理由是没有意义的,他的意义在于构造lazy function 以及 数据结构 - Clojure 里面非常实用的东西 - 并且在别的lisp语言里比较稀有。
让我们开始吧。
rember-f 它包含一个list,一个atom, 一个比较函数,如下解释
1 2 3 4 5 6 7 8 9 10 11
;demonstrating passing functions around (def rember-f (fn [test? a l] (cond (null? l) '() true (cond (test? (first l) a) (rest l) true (cons (first l) (rember-f test? a (rest l))))))) (println (rember-f = '(pop corn) '(lemonade (pop corn) and (cake)))) ;//=>(lemonade and (cake))
我们把 (=) 作为比较函数,用来去掉list 里面于a相同的atom
1 2 3 4 5 6 7 8 9 10
; 简化版 (def rember-f (fn [test? a l] (cond (null? l) '() (test? (first l) a) (rest l) true (cons (first l) (rember-f test? a (rest l)))))) (println (rember-f = '(pop corn) '(lemonade (pop corn) and (cake)))) ;//=>(lemonade and (cake))
(def seqL (fn [new old l] (cons new (cons old l)))) (def seqR (fn [new old l] (cons old (cons new l)))) (def insert-g (fn [seqarg] (fn [new old l] (cond (null? l) '() (= (first l) old) (seqarg new old (rest l)) true (cons (first l) ((insert-g seqarg) new old (rest l))))))) (def insertL (insert-g seqL)) (println (insertL 'creamy 'latte '(a hot cup of latte))) ;//=>(a hot cup of creamy latte) (def insertR (insert-g seqR)) (println (insertR 'cake 'cheese '(new york cheese))) ;//=>(new york cheese cake)
利用上面的提取公因式的代码 重构 insertL
1 2 3 4 5 6
(def insertL (insert-g (fn [new old l] (cons new (cons old l))))) (println (insertL 'creamy 'latte '(a hot cup of latte))) ;//=>(a hot cup of creamy latte)
(def subst (fn [new old l] (cond (null? l) '() (= (first l) old) (cons new (rest l)) true (cons (first l) (subst new old (rest l)))))) (println (subst 'espresso 'latte '(a hot cup of latte))) ;//=>(a hot cup of espresso)
(def seqS (fn [new old l] (cons new l))) (def subst (insert-g seqS)) (println (subst 'espresso 'latte '(a hot cup of latte))) ;//>(a hot cup of espresso)
下面重构 rember
1 2 3 4 5 6 7 8 9 10
(def seqrem (fn [new old l] l)) (def rember (fn [a l] ((insert-g seqrem) nil a l))) (println (rember 'hot '(a hot cup of espresso))) ;//=>(a cup of espresso)
第十要义:
“Abstract functions with common structures into a single function”
(def member? " a is a member of lat?" (fn [a lat] (cond (null? lat) false :else (or (= (first lat) a) (member? a (rest lat)))) )) (def subset? (fn [set1 set2] "set1 is subset of set2 ?" (cond (null? set1) true :else (and (member? (first set1) set2) (subset? (rest set1) set2))))) (println (subset? '(a b c) '(b c d))) ;//=>false (println (subset? '(b c) '(b c d))) ;//=>true (def intersect? "if set1 has at least one atom in set2" (fn [set1 set2] (cond (null? set1) false :else (or (member? (first set1) set2) (intersect? (rest set1) set2))))) (println (intersect? '(a b c) '(b c d))) ;//=>true
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/and, compiling:(/Users/caorong/Documents/workspace_clojure/little-schemer/src/little_schemer/chapter8.clj:161:14)
(def function-maker (fn [future] ((fn [recfun] (fn [l] (cond (null? l) '() (= (first l) 'curry) (recfun (rest l)) true (cons (first l) ((future future)))))) (fn [arg] ((future future) arg))))) ;abstraction above to remove l ; just take my word on this for now
;using add1 from chapter 7 not chapter 4 (def add1 (fn [n] (cons '() n))) ; now we'll look at using the y-combinator to look at the length of a list (def L (fn [recfun] (fn [l] (cond (null? l) '() true (add1 (recfun (rest l))))))) (def length (Y L)) (println (length '(curry chicken with curry rice))) ;//=>(() () () () ()) ie 5
下面我们重定义了add1, 并且把 L 作为匿名函数定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
(def add1 (fn [n] (+1 n))) ;just for the sake of it - we'll rewrite length without the L function (def length (Y (fn [recfun] (fn [l] (cond (null? l) 0 true (add1 (recfun (rest l)))))))) (println (length '(curry chicken with curry rice))) ;//=>5