Recursion 如何根据reduce定义map、filter和reverse等操作?
在本博客中,作者陈述: 首先,我们必须认识到许多数组(或其他集合)操作,如Recursion 如何根据reduce定义map、filter和reverse等操作?,recursion,clojure,functional-programming,reduce,fold,Recursion,Clojure,Functional Programming,Reduce,Fold,在本博客中,作者陈述: 首先,我们必须认识到许多数组(或其他集合)操作,如map、filter和reverse可以根据reduce定义 我的问题是:如何根据reduce定义map、filter和reverse等操作?您能提供Clojure中的示例吗?如果我们不关心懒惰,这是真的。在Clojure中,map和filter是懒惰的,而reduce是急切的。不仅reverse不懒惰,而且标准定义使用reduce。以惰性为模,我们可以得到其他的等效结果: user> (defn eager-map
map
、filter
和reverse
可以根据reduce
定义
我的问题是:如何根据reduce定义map、filter和reverse等操作?您能提供Clojure中的示例吗?如果我们不关心懒惰,这是真的。在Clojure中,
map
和filter
是懒惰的,而reduce是急切的。不仅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)
编辑以识别
mapv
和filterv
标准<代码>反向是根据<代码>减少定义的:
(defn reverse [coll]
(reduce conj () coll))
map
和filter
是惰性的,因此可以对无限序列进行操作。使用reduce
无法做到这一点
这就是说,reduce
可以实现和,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))))
如果我们在向量中累积,我们可以不使用
反向
s和向量
s:
(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
的实现方式
如何根据reduce定义map、filter和reverse等操作
这就是我们所知道的<代码>折叠以下是自然折叠(foldr):
显然,各种减少可以通过fold来描述:
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 :: (a -> Bool) -> ([a] -> [a])
filter p = fold (\x xs -> if p x then x : xs else xs) []
甚至向左折叠
:
foldl f v xs = fold (\x g -> (\a -> g (f a x))) id xs v
参考资料:
这是一个奇怪的地方使用
concat
,为了减少您选择自己的基本情况,所以选择一个具有所需conj
行为的。为什么conj
用于反转,而cons
(和外部反转)用于映射/过滤器?@user2864740 inreverse
,(defn conj[coll x]…)
的参数顺序正确,适用于reduce
cons
需要包装在一个函数中,并反转其参数:#(cons%2%1)
。在map
中,reduce
中的cons
会叠加结果,从而反转结果,因此需要再次反转。这同样适用于过滤器
。Clojure的习惯用法是在这种情况下使用向量-避免需要反转产品。我已经附加了这样做的版本。请注意,如果有人对它们使用conj
或disj
,这些将以序列形式返回。@user2864740上次编辑使我的部分答复无效。很荣幸您能回答我的问题。Haskell的人为了接触Clojure社区所做的所有工作都很棒。我现在正在通过RWH工作,直到第7通道。@hawkeye什么工作,hawkeye?我很好奇。是Clojure Haskell的斗牛犬吗?就像赫胥黎是达尔文的斗牛犬一样。@Thumbnail.“.对于纯函数代码还没有决定,但尽管如此,他还是全心全意地支持函数编程…”似乎这个类比是可行的;-)