Skip to content

Commit 1f08701

Browse files
updated functional examples
1 parent 7758eac commit 1f08701

12 files changed

+207
-63
lines changed

examples/functional.clj

+45-45
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
(ns examples.functional)
22

33
; START: stack-consuming-fibo
4+
; bad idea
45
(defn stack-consuming-fibo [n]
56
(cond
67
(= n 0) 0 ; <label id="code.stack-consuming-fibo.0"/>
@@ -9,7 +10,7 @@
910
; END: stack-consuming-fibo
1011

1112
; START: tail-recursive-fibo
12-
; beware: still consumes stack!
13+
; also bad: still consumes stack!
1314
(defn tail-recursive-fibo [n]
1415
(cond
1516
(= n 0) 0
@@ -23,6 +24,7 @@
2324
; END: tail-recursive-fibo
2425

2526
; START: loop-recur-fibo
27+
; better but not great
2628
(defn loop-recur-fibo [n]
2729
(cond
2830
(= n 0) 0
@@ -35,7 +37,8 @@
3537
; END: loop-recur-fibo
3638

3739
; START: fibo-series
38-
; returns series to n (heap-consuming!)
40+
; returns series to n
41+
; still bad (heap-consuming!)
3942
(defn fibo-series [count]
4043
(let [n (dec count)]
4144
(cond
@@ -60,33 +63,6 @@
6063
(def head-fibo (lazy-cat [0 1] (map + head-fibo (rest head-fibo))))
6164
; END: head-fibo
6265

63-
; inspired by http://www.cs.uni.edu/~wallingf/patterns/recursion.html
64-
(defn symbol-replace [coll oldsym newsym]
65-
(if (empty? coll)
66-
()
67-
(let [f (first coll)]
68-
(if (symbol? f)
69-
(lazy-cons (if (= f oldsym) newsym f)
70-
(symbol-replace (rest coll) oldsym newsym))
71-
(lazy-cons (symbol-replace f oldsym newsym)
72-
(symbol-replace (rest coll) oldsym newsym))))))
73-
74-
(declare h-male h-female)
75-
(defn h-male [n]
76-
(if (= n 0)
77-
0
78-
(- n (h-female (h-male (dec n))))))
79-
80-
(defn h-female [n]
81-
(if (= n 0)
82-
1
83-
(- n (h-male (h-female (dec n))))))
84-
(def h-male (memoize h-male))
85-
(def h-female (memoize h-female))
86-
87-
(def h-male-seq (map h-male (iterate inc 0)))
88-
(def h-female-seq (map h-female (iterate inc 0)))
89-
9066
; START: count-heads-pairs
9167
(defn count-heads-pairs [coll]
9268
(loop [cnt 0 coll coll] ; <label id="code.count-heads-loop.loop"/>
@@ -110,21 +86,29 @@
11086
(defn count-heads-pairs [coll]
11187
(count (filter (fn [pair] (every? #(= :h %) pair))
11288
(by-pairs coll))))
89+
; END: count-heads-by-pairs
11390
(def count-heads-by-pairs count-heads-pairs)
114-
; START: count-heads-by-pairs
11591

116-
(def
117-
#^{:doc "Count items matching a predicate."
118-
:arglists '([pred coll])}
119-
count-if (comp count filter))
92+
; START: count-if
93+
(use '[clojure.contrib.def :only (defvar)])
94+
(defvar count-if (comp count filter) "Count items matching a filter")
95+
; END: count-if
12096

97+
; START: count-runs
12198
(defn
12299
count-runs
123100
"Count runs of length n where pred is true in coll."
124101
[n pred coll]
125102
(count-if #(every? pred %) (partition n 1 coll)))
103+
; END: count-runs
126104

105+
; START: count-heads-by-runs
106+
(defvar count-heads-pairs (partial count-runs 2 #(= % :h))
107+
"Count runs of length two that are both heads")
108+
; END: count-heads-by-runs
109+
(def count-heads-by-runs count-heads-pairs)
127110

111+
; START: my-odd-even
128112
(declare my-odd? my-even?)
129113

130114
(defn my-odd? [n]
@@ -136,15 +120,32 @@ count-if (comp count filter))
136120
(if (= n 0)
137121
true
138122
(my-odd? (dec n))))
139-
140-
(defn my-parity? [parity n]
141-
(if (= n 0)
142-
(= parity 0)
143-
(recur (- 1 parity) (dec n))))
144-
145-
(def my-even-2? (partial my-parity? 0))
146-
(def my-odd-2? (partial my-parity? 1))
147-
123+
; END: my-odd-even
124+
125+
; START: parity
126+
(defn parity [n]
127+
(loop [n n par 0]
128+
(if (= n 0)
129+
par
130+
(recur (dec n) (- 1 par)))))
131+
; END: parity
132+
133+
; START: my-odd-even-parity
134+
(defn my-even? [n] (= 0 (parity n)))
135+
(defn my-odd? [n] (= 1 (parity n)))
136+
; END: my-odd-even-parity
137+
138+
; START: curry
139+
; almost a curry
140+
(defn curry [f]
141+
(fn [& front]
142+
(fn [& back]
143+
(apply f (concat front back)))))
144+
; END: curry
145+
146+
; --------------------------------------------------------------------------------------
147+
; -- See www.cs.brown.edu/~sk/Publications/Papers/Published/sk-automata-macros/paper.pdf
148+
; --------------------------------------------------------------------------------------
148149
(defn machine [stream]
149150
(let [step {[:init 'c] :more
150151
[:more 'a] :more
@@ -175,5 +176,4 @@ count-if (comp count filter))
175176
(when-not (seq stream) true))
176177

177178

178-
179-
179+

examples/male_female.clj

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
(ns examples.male-female)
2+
3+
; START: m-f
4+
; do not use these directly
5+
(declare m f)
6+
(defn m [n]
7+
(if (= n 0)
8+
0
9+
(- n (f (m (dec n))))))
10+
11+
(defn f [n]
12+
(if (= n 0)
13+
1
14+
(- n (m (f (dec n))))))
15+
; END: m-f
16+

examples/male_female_seq.clj

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(ns examples.male-female-seq
2+
(use [clojure.contrib.def :only (defvar-)]))
3+
4+
(declare m f)
5+
(defn- m [n]
6+
(if (= n 0)
7+
0
8+
(- n (f (m (dec n))))))
9+
10+
(defn- f [n]
11+
(if (= n 0)
12+
1
13+
(- n (m (f (dec n))))))
14+
15+
(defvar- m (memoize m))
16+
(defvar- f (memoize f))
17+
18+
; START: m-f-seq
19+
(def m-seq (map m (iterate inc 0)))
20+
(def f-seq (map f (iterate inc 0)))
21+
; END: m-f-seq
22+

examples/memoized_male_female.clj

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
(ns examples.memoized-male-female)
2+
3+
(declare m f)
4+
(defn- m [n]
5+
(if (= n 0)
6+
0
7+
(- n (f (m (dec n))))))
8+
9+
(defn- f [n]
10+
(if (= n 0)
11+
1
12+
(- n (m (f (dec n))))))
13+
14+
; START: m-f-memoize
15+
(def m (memoize m))
16+
(def f (memoize f))
17+
; END: m-f-memoize
18+

examples/symbol_replace.clj

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
(ns examples.symbol-replace)
2+
3+
; inspired by http://www.cs.uni.edu/~wallingf/patterns/recursion.html
4+
(defn- coll-or-scalar [x & _] (if (coll? x) :collection :scalar))
5+
(defmulti symbol-replace coll-or-scalar)
6+
7+
(defmethod symbol-replace :collection [coll oldsym newsym]
8+
(if (empty? coll)
9+
coll
10+
(cons (symbol-replace (first coll) oldsym newsym)
11+
(symbol-replace (rest coll) oldsym newsym))))
12+
13+
(defmethod symbol-replace :scalar [obj oldsym newsym]
14+
(if (= obj oldsym) newsym obj))
15+
16+
;; (defn symbol-replace [coll oldsym newsym]
17+
;; (if (empty? coll)
18+
;; coll
19+
;; (let [f (first coll)]
20+
;; (if (symbol? f)
21+
;; (lazy-cons (if (= f oldsym) newsym f)
22+
;; (symbol-replace (rest coll) oldsym newsym))
23+
;; (lazy-cons (symbol-replace f oldsym newsym)
24+
;; (symbol-replace (rest coll) oldsym newsym))))))
25+
26+

examples/test.clj

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
:sequences :index-of-any :life-without-multi :multimethods.default
1010
:macros :macros.chain-1 :macros.chain-2 :macros.chain-3 :macros.chain-4
1111
:macros.chain-5 :lazy-index-of-any :macros.bench-1
12-
:concurrency :functional :snake :snippet]))
12+
:concurrency :functional :snake :snippet :symbol-replace
13+
:male-female :memoized-male-female :male-female-seq]))
1314

1415
(def lancet-tests
1516
(map #(symbol (str "lancet.test." (name %)))

examples/test/functional.clj

+1-17
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,8 @@
2525
(deftest test-head-fibo
2626
(is (= ten-fibs (take 10 head-fibo))))
2727

28-
(deftest test-symbol-replace
29-
(are (= _1 _2)
30-
() (symbol-replace () 'a 'b)
31-
'(a) (symbol-replace '(a) 'b 'c)
32-
'(c) (symbol-replace '(b) 'b 'c)
33-
'(a (d e)) (symbol-replace '(a (d e)) 'b 'c)
34-
'(c (c c)) (symbol-replace '(b (b b)) 'b 'c)
35-
))
36-
37-
(deftest test-hofstadter-m-f
38-
(are (= _1 _2)
39-
[0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 12]
40-
(map h-male (range 0 21))
41-
[1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11, 11, 12, 13]
42-
(map h-female (range 0 21))))
43-
4428
(deftest test-count-heads-pairs
45-
(doseq [count-fn [count-heads-loop count-heads-by-pairs]]
29+
(doseq [count-fn [count-heads-loop count-heads-by-pairs count-heads-by-runs]]
4630
(are (= _1 _2)
4731
0 (count-fn [:h :t])
4832
1 (count-fn [:t :h :h :t])

examples/test/male_female.clj

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
(ns examples.test.male-female
2+
(:use clojure.contrib.test-is
3+
examples.male-female))
4+
5+
(deftest test-hofstadter-m-f
6+
(are (= _1 _2)
7+
[0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 12]
8+
(map m (range 21))
9+
[1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11, 11, 12, 13]
10+
(map f (range 21))))
11+

examples/test/male_female_seq.clj

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
(ns examples.test.male-female-seq
2+
(:use clojure.contrib.test-is
3+
examples.male-female-seq))
4+
5+
(deftest test-hofstadter-m-f
6+
(are (= _1 _2)
7+
[0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 12]
8+
(take 21 m-seq)
9+
[1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11, 11, 12, 13]
10+
(take 21 f-seq)))
11+
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
(ns examples.test.memoized-male-female
2+
(:use clojure.contrib.test-is
3+
examples.memoized-male-female))
4+
5+
(deftest test-hofstadter-m-f
6+
(are (= _1 _2)
7+
[0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 12]
8+
(map m (range 21))
9+
[1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11, 11, 12, 13]
10+
(map f (range 21))))
11+

examples/test/symbol_replace.clj

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
(ns examples.test.symbol-replace
2+
(:use clojure.contrib.test-is
3+
examples.symbol-replace))
4+
5+
(deftest test-symbol-replace
6+
(are (= _1 _2)
7+
() (symbol-replace () 'a 'b)
8+
'(a) (symbol-replace '(a) 'b 'c)
9+
'(c) (symbol-replace '(b) 'b 'c)
10+
'(a (d e)) (symbol-replace '(a (d e)) 'b 'c)
11+
'(c (c c)) (symbol-replace '(b (b b)) 'b 'c)
12+
))
13+

examples/trampoline.clj

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
(ns examples.trampoline)
2+
3+
; START: tail-recursive-fibo
4+
; Example only. Don't write code like this.
5+
(defn tail-recursive-fibo [n]
6+
(cond
7+
(= n 0) 0
8+
(= n 1) 1
9+
true ((fn fib [f-2 f-1 current]
10+
(let [f (+ f-2 f-1)]
11+
(if (= n current)
12+
f
13+
#(fib f-1 f (inc current))))) ; <label id="code.tail-recursive-fibo.trampoline"/>
14+
0 1 2)))
15+
; END: tail-recursive-fibo
16+
17+
; START: odd-even
18+
(declare my-odd? my-even?)
19+
20+
(defn my-odd? [n]
21+
(if (= n 0)
22+
false
23+
#(my-even? (dec n)))) ; <label id="code.trampoline.my-odd"/>
24+
25+
(defn my-even? [n]
26+
(if (= n 0)
27+
true
28+
#(my-odd? (dec n)))) ; <label id="code.trampoline.my-even"/>
29+
; END: odd-even
30+
31+

0 commit comments

Comments
 (0)