Haskell -- 用foldr表示foldl

来源:互联网 发布:php门户网站 编辑:程序博客网 时间:2024/06/06 09:08

Real World Haskell的哥仨写到foldr表示foldl时:

" Understanding foldl in terms of foldr.

If you want to set yourself a solid challenge, try to follow the above definition offoldl using foldr. Be warned: this is not trivial! You might want to have the following tools at hand: some headache pills and a glass of water,ghci (so that you can find out what theid function does), and a pencil and paper. "

请准备好阿司匹林,一打纸,一只新笔,谢谢。

书中没给答案和解释,引得众人吐槽不已,后来 Don Stewar (上书哥仨之一)在stackoverflow

http://stackoverflow.com/questions/6172004/writing-foldl-using-foldr

上回了篇长文。

最早Graham Hutton在 A tutorial on the universality and expressiveness of fold 中介绍了这个trick:

      foldl f acc xs = foldr (\x g s -> g (f s x)) id xs acc

或者

      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)


以下以myFoldl为例(个人更喜欢第一个,表达更清晰),继续之前,需要对foldl和foldr熟悉。

fold是控制结构的函数,参数 f 是干活函数,进行实际计算。相当于PM与码农。


现在 foldl 带领 f 开发出产品 a,即 a = foldl f z xs,
另一pm foldr不干了,要求在他的指导下,开发出同 foldl 功能及体验一样的产品。

两者框架不同,要求结果一致,码农表示压力很大。
看来不能像f一样只傻干活,也需要进行结构调整,以满足 foldr变性的需求。

于是 step,
一方面雇佣 f 干活, 达到功能相同;
一方面在foldr的架构下,在进行重组,达到体验一致。

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)

步骤如下:
   foldr step id (x:xs) z             -- apply foldr
= step x (foldr step id xs) z    -- apply step
= (foldr step id xs) (f z x)        -- 'f z x' updates accumulator just like foldl's 'f z s'
go on ...    
.......
.......
-- at last, encounter the empty list.  foldr _ acc [] = acc
= (foldr step id []) sth
= id sth
= sth

It simulates the foldl computation process, namely, every time it controls 'f'

applying to the accumulator and an element of the list as the new accumulator.


It is not that hard, right ? Hope your pen still has ink to remain your next re-practice of foldl & foldr.

In my experience, you should at least do it three times then you may say I really know it.




原创粉丝点击