在此博客文章"CSP and transducers in JavaScript"中,作者声明:
首先,我们必须意识到,
map
,filter
和reverse
等许多数组(或其他集合)操作都可以用reduce
来定义。< / p>
我的问题是:如何通过缩减来定义地图,过滤器和反向等操作?您能否在Clojure中提供示例?
答案 0 :(得分:5)
已修改以识别mapv
和filterv
。
标准reverse
按<{1}}定义:
reduce
(defn reverse [coll]
(reduce conj () coll))
和map
是懒惰的,因此可以对无限序列进行操作。使用filter
无法执行此操作。
话虽如此,reduce
可以实现reduce
和mapv
,这是map
和filter
的热切类比。
(defn mapv [f coll]
(vec (reverse (reduce (fn [acc x] (cons (f x) acc)) () coll))))
(defn filterv [pred coll]
(vec (reverse (reduce (fn [acc x] (if (pred x) (cons x acc) acc)) () coll))))
如果我们在向量中累积,我们可以不使用reverse
和vec
:
(defn mapv [f coll]
(reduce (fn [acc x] (conj acc (f x))) [] coll))
(defn filterv [pred coll]
(reduce (fn [acc x] (if (pred x) (conj acc x) acc)) [] coll))
这最后几乎是标准filterv
的实现方式。
答案 1 :(得分:5)
如何根据reduce?
来定义map,filter和reverse等操作
这被称为"universality of fold"。下面fold
是自然折叠(foldr):
显然,可以通过折叠来描述各种减少:
sum :: [Int] -> Int product :: [Int] -> Int
sum = fold (+) 0 product = fold (*) 1
and :: [Bool] -> Bool or :: [Bool] -> Bool
and = fold (&&) True or = fold (||) False
但我们也可以写出非明显的减少:
-- appending a list
(++) :: [a] -> [a] -> [a]
(++ ys) = fold (:) ys
-- reversing a list
reverse :: [a] -> [a]
reverse = fold (\x xs -> xs ++[x]) []
和map
一般:
map :: (a -> b) -> ([a] -> [b])
map f = fold (\x xs -> f x : xs) []
或filter
:
filter :: (a -> Bool) -> ([a] -> [a])
filter p = fold (\x xs -> if p x then x : xs else xs) []
甚至fold left
:
foldl f v xs = fold (\x g -> (\a -> g (f a x))) id xs v
参考文献:
答案 2 :(得分:3)
如果我们不关心懒惰,这是事实。在Clojure中,map
和filter
是懒惰的,但减少是渴望的。 reverse
不仅不是懒惰,而且标准定义使用reduce。模数懒惰,我们可以得到与其他人相同的结果:
user> (defn eager-map [f coll]
(reduce (fn [acc v] (conj acc (f v)))
[]
coll))
#'user/eager-map
user> (eager-map inc (range 10))
[1 2 3 4 5 6 7 8 9 10]
user> (defn eager-filter [f coll]
(reduce (fn [acc v] (if (f v) (conj acc v) acc))
[]
coll))
#'user/eager-filter
user> (eager-filter even? (range 10))
[0 2 4 6 8]
user> (defn eager-reverse [coll]
(reduce conj () coll))
#'user/eager-reverse
user> (eager-reverse (range 10))
(9 8 7 6 5 4 3 2 1 0)