根据文件夹定义文件夹

时间:2018-10-30 05:25:43

标签: haskell fold foldleft

myFoldl :: (a -> b -> a) -> a -> [b] -> a

myFoldl f z xs = foldr step id xs z
    where step x g a = g (f a x)

我目前正在阅读有关Haskell的书。并且在其中,它编写了自己的foldl函数版本,但是使用了foldr。我不跟随。

  1. 为什么foldr有4个参数?
  2. id函数有什么作用?

2 个答案:

答案 0 :(得分:3)

扩展foldr step id xs z的表达式时,事情将变得显而易见:

如亚当·斯密(Adam Smith)在评论中所说:

  

文件夹步骤ID xs z =(文件夹步骤id xs)z

首先考虑foldr step id xs

foldr step id xs
= x1 `step` (foldr step id xs1)
= x1 `step` (x2 `step` (foldr step id xs2))
...
= x1 `step` (x2 `step` ... (xn `step` (foldr step id []))...)
= x1 `step` (x2 `step` ... (xn `step` id)...)

其中

xs = (x1:xs1)
xs1 = (x2:xs2), xs = (x1:x2:xs2) 
....
xsn = (xn:[]), xs = (x1:x2...xsn) respectively 

现在,将上面的函数与参数z一起应用,即

(x1 `step` (x2 `step` ... (xn `step` id)...)) z

然后让

g = (x2 `step` ... (xn `step` id)...) 

给予

(x1 `step` g) z

(step x1 g) z

现在应用foldl的where部分:

  

其中步骤x g a = g(f a x)

给予

(step x1 g) z = step x1 g z = g (step z x1)

其中

g (step z x1) = (x2 `step` (x3 step ... (xn `step` id)...) (step z x1)

g' = (x3 step ... (xn `step` id)...)

给予

(x2 `step` g') (step z x1)
= step x2 g' (step z x1)
= g' (step (step z x1) x2))
= (x3 step ... (xn `step` id)...) (step (step z x1) x2))

重复相同的步骤,最后我们有了

(xn `step` id) (step ....(step (step z x1) x2)....)
= step xn id (step ....(step (step z x1) x2)....)
= id (step (step ....(step (step z x1) x2)....) xn)
= (step (step ....(step (step z x1) x2)....) xn)
= foldl step z xs

现在,很明显为什么要使用id函数。最后,看看为什么

foldl step z xs = (step (step ....(step (step z x1) x2)....) xn)

初始情况:

foldl step z' [] = z'

递归案例:

foldl step z (x1:xs1) 
= foldl step (step z x1) xs1
= foldl step (step (step z x1) x2) xs2
...
= foldl step (step (step ....(step (step z x1) x2)....) xn) []
= (step (step ....(step (step z x1) x2)....) xn)

其中

z' = (step (step ....(step (step z x1) x2)....) xn) in initial case

与上述相同。

答案 1 :(得分:1)

正如Adam Smith在评论中所说,foldr只有三个参数。有问题的行像这样被解析:

myFoldl f z xs = (foldr step id xs) z

当然也有其他隐式括号,但这是重要的。

这里是使用类型注释的重写,假设范围内的类型变量(即ab在整个定义中表示相同的类型)。

myFoldl :: (a -> b -> a) -> a -> [b] -> a
myFoldl f z xs =  goFold z
   where
      goFold :: a -> a
      goFold = foldr step id xs
      step :: b -> (a -> a) -> (a -> a)  -- Last brackets are redundant
      step x g a = g (f a x)

我将foldr调用移到了一个单独的值goFold中,因此您可以看到其类型以及如何将其应用于z值。 step函数将b的值累加到类型(a -> a)的函数中。由b处理的每个goFold值都添加了其中的一个。函数的“零”当然是前奏中的id

id :: a -> a
id x = x

类型中的->函数运算符是右关联的,因此step类型中的最后一对括号是多余的。但是我之所以这样写是因为它突显了step的使用方式。它需要一个值和一个函数并返回一个新函数。