We can see that we can use reduce
/foldl1
as the function by which we can define other higher order functions such as map, filter and reverse.
(defn mapl [f coll]
(reduce (fn [r x] (conj r (f x)))
[] coll))
(defn filterl [pred coll]
(reduce (fn [r x] (if (pred x) (conj r x) r))
[] coll))
(defn mapcatl [f coll]
(reduce (fn [r x] (reduce conj r (f x)))
[] coll))
We also appear to be able to do this in terms of foldr
. Here is map
and filter
in terms of foldr
from Rich Hickey's Transducers talk at 17:25.
(defn mapr [f coll]
(foldr (fn [x r] (cons (f x) r))
() coll))
(defn filterr [pred coll]
(foldr (fn [x r] (if (pred x) (cons x r) r))
() coll))
Now we can define map
, foldl
(reduce
) and foldr
in terms of first
, rest
and cons
(car
, cdr
and cons
):
(defn foldr [f z xs]
(if (null? xs)
z
(f (first xs) (foldr f z (rest xs)))))
(defn foldl [f z xs]
(if (null? xs)
z
(foldl f (f z (first xs)) (rest xs))))
(defn map [f lst]
(if (null? lst)
'()
(cons (f (first lst)) (map f (rest lst)))))
My question is Why is fold
and reduce
considered fundamental - surely everything is defined in terms of cons
, cdr
and car
? Isn't this looking at things at the wrong level?