| |
| | (ns e2-33-to-39
(:use [util.util :only (zip)])
(:use clojure.test)
(:use [clojure.contrib.generic.math-functions :only (sqr)]))
| | (defn accumulate [f zero xs]
(if (empty? xs) zero
(f (first xs)
(accumulate f zero (rest xs)))))
| | (defn my-map [f xs]
(accumulate (fn [el acc]
(cons (f el) acc)) [] xs))
| | (deftest test-my-map
(is (= (my-map #(+ 1 %) [1 2 3]) [2 3 4])))
| | (defn append [xs ys]
(accumulate cons (rest ys) (if (nil? (first ys)) xs
(conj xs (first ys)))))
| | (deftest test-append
(is (= (append [1 2 3] [4 5 6]) [1 2 3 4 5 6]))
(is (= (append [] [1 2]) [1 2]))
(is (= (append [1 2] []) [1 2])))
| | (defn length [xs]
(accumulate #(+ 1 %2) 0 xs))
| | (deftest test-length
(is (= (length [1 2 3]) 3))
(is (= (length []) 0)))
| | (defn horner-eval [x coeff-seq]
(accumulate (fn [el acc]
(+ el (* (horner-eval x (rest coeff-seq)) x)))
0 coeff-seq))
| | (deftest test-horner-eval
(is (= (horner-eval 2 [1 3 0 5 0 1]) 79))
(is (= (horner-eval 2 []) 0)))
| | (defn count-leaves [t]
(accumulate (fn [el acc]
(if (sequential? el)
(+ (count-leaves el) acc)
(inc acc))) 0
t))
| | (deftest test-count-leaves
(is (= (count-leaves [1 [2 [3 4]] 7]) 5)))
| | (defn accumulate-n [op init seqs]
(if (empty? (first seqs))
nil
(cons (accumulate op init (map first seqs))
(accumulate-n op init (map rest seqs)))))
| | (deftest test-accumulate-n
(is (= (accumulate-n + 0 [[1 2 3] [4 5 6] [7 8 9] [10 11 12]]) [22 26 30])))
At first I made a big mistake of confusing the matrix representation used in this exercise (lists represent rows).
No wonder I couldn't write (matrix-times-vector) without transposing the argument matrix.
| | (defn dot-product [v w]
(accumulate + 0 (map * v w)))
| | (def *123v* [1 2 3])
(def *123m* [[1 1 1] [2 2 2] [3 3 3]])
| | (defn matrix-times-vector [m v]
; for each row in the matrix (m)
(map (fn [row]
(accumulate (fn [el acc]
(+ acc (* el (second row)))) 0
; I cheated here by zipping matrix with the vector
(first row))) (zip m v)))
| | (deftest test-times-vector
(is (= (matrix-times-vector *123m* *123v*) [3 12 27])))
| | (defn transpose [m]
(accumulate-n cons [] m))
| | (deftest test-transpose
(is (= (transpose *123m*) [*123v* *123v* *123v*])))
| | (defn matrix-times-matrix [m n]
(let [cols (transpose n)]
(map (fn [row]
; for each row element and col element, multiply them together and bind the resulting list of lists to (prods)
(let [prods (map #(accumulate-n * 1 [row %1]) cols)]
(map #(accumulate + 0 %1) prods)))
m)))
| | (deftest test-times-matrix
(is (= (matrix-times-matrix *123m* *123m*) [[6 6 6] [12 12 12] [18 18 18]])))
| | (defn foldl [f zero xs]
(letfn [(iter [result remaining]
(if (empty? remaining) result
(recur (f result (first remaining))
(rest remaining))))]
(iter zero xs)))
| | (deftest test-foldl
(is (= (accumulate + 0 [1 2 3]) (foldl + 0 [1 2 3])))
(is (not (= (accumulate - 0 [1 2 3]) (foldl - 0 [1 2 3]))))
; (/ 1 1) [2 3]
; (/ 1 2) [3]
; (/ 0.5 3) []
(is (= (foldl / 1 [1 2 3]) (/ (/ 1 2) 3)))
; (/ 1 1) [2 3]
; (/ 1 (/ 2) [3]
; (/ 1 (/ 2 (/ 3 1)))
(is (= (accumulate / 1 [1 2 3]) (/ 3 2)))
(is (= (foldl list nil [1 2 3]) [[[nil 1] 2] 3]))
(is (= (accumulate list nil [1 2 3]) [1 [2 [3 nil]]])))
Concerning the second part of the exercise (the question):
the operation passed into foldl and foldr should be associative in order for them to produce identical results (semigroup).
| |
| | (defn my-reverse-foldr [xs]
(accumulate (fn [x y]
(concat y [x])) nil xs))
| | (defn my-reverse-foldl [xs]
(foldl (fn [x y]
(cons y x)) nil xs))
| | (deftest test-my-reverse
(is (= (my-reverse-foldr [1 2 3]) [3 2 1]))
(is (= (my-reverse-foldl [1 2 3]) [3 2 1])))
| |