使用文件夹定义地图(开发)

时间:2019-02-02 17:15:28

标签: haskell fold currying

很难理解折叠...扩展正确吗?也将感谢任何链接或类比会使折叠更易消化。

foldMap :: (a -> b) -> [a] -> [b]
foldMap f [] = []
foldMap f xs = foldr (\x ys -> (f x) : ys) [] xs


b =  (\x ys -> (f x):ys)
foldMap (*2) [1,2,3]
= b 1 (b 2 (foldr b [] 3))
= b 1 (b 2 (b 3 ( b [] [])))
= b 1 (b 2 ((*2 3) : []))
= b 1 ((*2 2) : (6 :[]))
= (* 2 1) : (4 : (6 : []))
= 2 : (4 : (6 : []))

2 个答案:

答案 0 :(得分:6)

首先,我们不要使用名称foldMap,因为它已经是a standard function different from map。如果要使用相同或相似的语义重新实现现有功能,则约定为它赋予相同的名称,但可以在单独的模块中或在其后附加撇号'名字。另外,我们可以省略空列表的情况,因为您也可以将它传递给首屏:

map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\x ys -> f x : ys) [] xs

现在,如果您想手动评估此功能,请先使用该定义,而无需再插入其他内容:

map' (*2) [1,2,3,4]
 ≡ let f = (*2)
       xs = [1,2,3,4]
   in foldr (\x ys -> (f x) : ys) [] xs
 ≡ foldr (\x ys -> (*2) x : ys) [] [1,2,3,4]

现在只是美化一下:

 ≡ foldr (\x ys -> x*2 : ys) [] [1,2,3,4]

现在要对此进行评估,还需要定义foldr。实际上,GHC有点不同,但是有效

foldr _ z []     =  z
foldr f z (x:xs) =  f x (foldr f z xs)

以您的示例为例

  ...
 ≡ foldr (\x ys -> x*2 : ys) [] (1:[2,3,4])
 ≡ (\x ys -> x*2 : ys) 1 (foldr (\x ys -> x*2 : ys) [] [2,3,4])

现在我们可以进行β还原:

 ≡ 1*2 : foldr (\x ys -> x*2 : ys) [] [2,3,4]
 ≡ 2 : foldr (\x ys -> x*2 : ys) [] [2,3,4]

...然后重复递归。

答案 1 :(得分:5)

foldr定义了一系列方程,

foldr g n [] = n
foldr g n [x] = g x (foldr g n []) = g x n
foldr g n [x,y] = g x (foldr g n [y]) = g x (g y n)
foldr g n [x,y,z] = g x (foldr g n [y,z]) = g x (g y (g z n))
                        ----- r ---------

,依此类推。 g reducer 函数,

                    g x r = ....

接受输入列表的元素作为x,并接受递归处理 r的 r 结果作为r 输入列表中的大多数内容(如公式中所示)。

另一方面,

map定义了一系列方程式

map f [] = []
map f [x] = [f x] = (:) (f x) [] = ((:) . f) x []
map f [x,y] = [f x, f y] = ((:) . f) x (((:) . f) y [])
map f [x,y,z] = [f x, f y, f z] = ((:) . f) x (((:) . f) y (((:) . f) z []))
                                =  (:)  (f x) ( (:)  (f y) ( (:)  (f z) []))

两个家庭完全匹配

g = ((:) . f) = (\x -> (:) (f x)) = (\x r -> f x : r)

n = [],因此

foldr ((:) . f) [] xs  ==  map f xs

我们可以根据foldr的定义定律,通过对输入列表长度的数学归纳法来严格证明这一点,

foldr g n [] = []
foldr g n (x:xs) = g x (foldr g n xs)

是本文顶部等式的基础。

现代Haskell具有Fodable类型的类,其基本fold遵循……的定律

fold(<>,n) [] = n
fold(<>,n) (xs ++ ys) = fold(<>,n) xs <> fold(<>,n) ys

map的术语自然定义为

map f xs  =  foldMap (\x -> [f x]) xs

[x, y, z, ...]转换为[f x] ++ [f y] ++ [f z] ++ ...,因为对于列表(<>) == (++)。这是由于等价

    f x : ys  ==  [f x] ++ ys

这也使我们可以轻松地沿相同的行定义filter,就像

filter p xs  =  foldMap (\x -> [x | p x]) xs

对于您的特定问题,扩展名是正确的,除了(*2 x)应该写为((*2) x),它与(x * 2)相同。 (* 2 x)不是有效的Haskell(尽管有效的Lisp :))。

诸如(*2)之类的功能称为“ operator sections”-缺少的参数进入空白位置(* 2) 3 = (3 * 2) = (3 *) 2 = (*) 3 2

您还要求提供一些链接:例如,参见thisthisthis