Haskell 根据标准ML中的foldr定义foldl
定义的代码是Haskell 根据标准ML中的foldr定义foldl,haskell,functional-programming,sml,fold,Haskell,Functional Programming,Sml,Fold,定义的代码是 fun foldl f e l = let fun g(x, f'') = fn y => f''(f(x, y)) in foldr g (fn x => x) l e end 我不明白这是怎么回事; g(x,f')的目的是什么 我在Haskell也发现了一个类似的例子, 定义很短 myFoldl f z xs = foldr step id xs z where step x g a = g (f a x) 让我们分析一
fun foldl f e l = let
fun g(x, f'') = fn y => f''(f(x, y))
in foldr g (fn x => x) l e end
我不明白这是怎么回事;
g(x,f')
的目的是什么
我在Haskell也发现了一个类似的例子,
定义很短
myFoldl f z xs = foldr step id xs z
where
step x g a = g (f a x)
让我们分析一下
myFoldl
的Haskell实现,然后看看ocamlsml代码。首先,我们将了解一些类型签名:
foldr::(a->b->b)--步进函数
->b——累加器的初始值
->[a]——要折叠的列表
->b--结果如何
应该注意的是,尽管foldr
函数只接受三个参数,但我们应用了两个或四个参数:
foldr步骤id xs z
但是,正如您所看到的,foldr
(即累加器的初始值)的第二个参数是id
,它是x->x
类型的函数。因此,结果也是x->x
类型。因此,它接受四个论点
类似地,step函数现在是a->(x->x)->x->x
类型。因此,它接受三个参数,而不是两个参数。累加器是一个函数(即域和辅域相同的函数)
内函数有一个特殊的性质,它们是从左到右而不是从右到左组成的。例如,让我们组合一组Int->Int
函数:
inc::Int->Int
inc n=n+1
dbl::Int->Int
DBLn=n*2
合成这些函数的常规方法是使用函数合成运算符,如下所示:
incDbl::Int->Int
incDbl=inc。dbl
incDbl
函数首先将数字加倍,然后递增。请注意,这是从右向左读取的
组成它们的另一种方法是使用连续体(由k
表示):
inc':(Int->Int)->Int->Int
inc'kn=k(n+1)
dbl':(Int->Int)->Int->Int
dbl'kn=k(n*2)
请注意,第一个参数是一个延续。如果我们想恢复原始功能,我们可以:
inc::Int->Int
inc=inc'id
dbl::Int->Int
dbl=dbl'id
但是,如果我们想编写它们,那么我们将按如下方式进行:
incDbl':(Int->Int)->Int->Int
incDbl'=dbl'。公司
incDbl::Int->Int
incDbl=incDbl'id
请注意,尽管我们仍然使用点运算符来编写函数,但它现在从左向右读取
这是使foldr
表现为foldl
的关键。我们将列表从右向左折叠,但不是将其折叠成一个值,而是将其折叠成一个内函数,当应用于初始累加器值时,它实际上将列表从左向右折叠
考虑我们的incDbl
功能:
incDbl=incDbl'id
=(dbl'.inc')id
=dbl'(inc'id)
现在考虑<代码> FordR < /代码>:
foldr::(a->b->b)->b->[a]->b
foldr_uuACC[]=acc
foldr fun acc(y:ys)=fun y(foldr fun acc ys)
在基本情况下,我们只返回累积值。然而,在归纳的情况下,我们返回funy(foldr-fun-acc-ys)
。我们的步骤
功能定义如下:
step::a->(x->x)->x->x
步骤x g a=g(f a x)
这里的f
是foldl
的减速器函数,类型为x->a->x
。请注意,步骤x
是(x->x)->x->x
类型的内函数,我们知道它可以从左到右组合
因此,列表[y1,y2..yn]
上的折叠操作(即折叠步骤id
)如下所示:
步骤y1(步骤y2(…(步骤yn id)))
--或
(步骤y1.步骤y2.{dots}.步骤yn)id
每个步骤yx
都是一个内函数。因此,这相当于从左到右组合内函数
当此结果应用于初始累加器值时,列表将从左向右折叠。因此,myFoldl f z xs=foldr步骤id xs z
现在考虑<代码> FooLDL/COD>函数(用标准ML编写,而不是OCAML)。其定义如下:
fun foldl f e l=让fun g(x,f'')=fn y=>f''(f(x,y))
在foldr g(fn x=>x)l e end中
Haskell和SML的foldr
函数之间的最大区别是:
a->b->b
(a,b)->b
id
函数是SML中的匿名fn x=>x
函数step
函数是SML中的g
函数,它接受包含前两个参数的元组step
函数是Haskellstep x g a
在SMLg(x,f'')=fn y=>f''(f(x,y))
中被分成两个函数,以更清楚地说明问题fun myFoldl f z xs=let step(x,g)=fn a=>g(f(a,x))
在foldr步骤中(fn x=>x)xs z结束
因此,它们是完全相同的函数。表达式g(x,f')
只是将函数g
应用于元组(x,f')
。这里的f'
是一个有效的标识符。
foldl函数在使用累加器操作元素时从头到尾遍历列表:
(……(a)⊗x1)⊗...⊗xn-1)⊗xn
您想通过foldr定义它:
x1⊕(x2⊕...⊕(xn⊕e) …)
<
foldr ⊕ [1,2,3] id
-> 1⊕(2⊕(3⊕id))
-> 1⊕(2⊕(id.(+3))
-> 1⊕(id.(+3).(+2))
-> (id.(+3).(+2).(+1))
(id.(+3).(+2).(+1)) 0
= ((0+1)+2)+3
n ⊕ g = g . (+n)
foldl (+) 0 xs = foldr ⊕ id xs 0
where n ⊕ g = g . (+n)
foldl (+) 0 xs = foldr ⊕ id xs 0
where (⊕) n g a = g (a+n)
h [] = e
h (x:xs) = f x (h xs)
iff
h = foldr f e
h xs a = foldl f a xs
h xs = \a -> foldl f a xs
h [] = \a -> foldl f a []
= \a -> a
= id
h (x:xs) = \a -> foldl f a (x:xs)
= \a -> foldl f (f a x) xs
= \a -> h xs (f a x)
= step x (h xs) where step x g = \a -> g (f a x)
= step x (h xs) where step x g a = g (f a x)
h [] = id
h (x:xs) = step x (h xs) where step x g a = g (f a x)
h = foldr step id
h xs a = foldl f a xs
-----------------------
foldl f a xs = foldr step id xs a
where step x g a = g (f a x)