我是Haskell的新手并尝试了解地图功能。
到目前为止我理解以下内容。
map::(a->b)->[a]->[b]
map f (x:xs) = f x : map f xs
但我不明白以下定义: 使用 foldr 定义地图
map'::(a->b)->[a]->[b]
map' f = foldr ( (:).f ) []
任何人都可以解释上面的地图'定义以及为什么与地图相同
答案 0 :(得分:5)
让我们看一下the source of foldr
:
foldr k z = go where
go [] = z
go (x:xs) = k x (go xs)
现在让我们将map
的定义与上面go
的定义进行比较:
map f [] = []
map f (x:xs) = f x : map f xs
它看起来非常相似,不是吗?让我们重写第二个子句,将x
与递归调用结果相结合的部分拉出来:
map f [] = []
map f (x:xs) = (\v vs -> f v : vs) x (map f xs)
现在平行非常清楚;我们甚至可以写一些名字来结晶并行:
map f [] = z where z = []
map f (x:xs) = k x (map f xs) where k = \v vs -> f v : vs
只需在上面看到go
的任何地方替换map f
,您就会看到定义相同!因此,本着DRY的精神,我们可以尝试重用foldr
来实现上述目标:
map f = foldr (\v vs -> f v : vs) []
这让您了解如何从map
转到foldr
。一直到你给出的定义只是一些语法技巧。我们现在专注于foldr
的函数参数:
\v vs -> f v : vs
= { writing the infix operator prefix instead }
\v vs -> (:) (f v) vs
= { eta reduction }
\v -> (:) (f v)
= { definition of function composition }
\v -> ((:) . f) v
= { eta reduction }
(:) . f
因此,使用这种推理链,我们可以达到最终形式
map f = foldr ((:) . f) []
答案 1 :(得分:3)
另一个答案,希望某些人更容易获得。
foldr f z xs
将:
中的xs
替换为f
,将[]
替换为z
。所以
a : b : c : d : []
成为
a `f` b `f` c `f` d `f` z
现在让我们从map'
的定义中替换值。
a `(:).f` b `(:).f` c `(:).f` d `(:).f` []
(我稍微扩展了Haskell语法)。
现在,
a `(:).f` as
与
相同(:) (f a) as
与
相同f a : as
继续这种转变,我们得到了
f a : f b : f c : f d : []
嘿,这似乎是直接map f
应用于[a,b,c,d]
,不是吗?
答案 2 :(得分:0)
首先你需要了解
passwordText
另一个是在cons之前应用函数foldr (:) []
,因此相当于map