在Real World Haskell中,第4章.函数式编程
用foldr写foldl:
-- file: ch04/Fold.hs
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)
Run Code Online (Sandbox Code Playgroud)
上面的代码让我很困惑,有人打电话给dps用一个有意义的名字重写它,使它更清晰:
myFoldl stepL zeroL xs = (foldr stepR id xs) zeroL
where stepR lastL accR accInitL = accR (stepL accInitL lastL)
Run Code Online (Sandbox Code Playgroud)
其他人,Jef G,通过提供一个例子并逐步展示基础机制,做得非常出色:
myFoldl (+) 0 [1, 2, 3]
= (foldR step id [1, 2, …Run Code Online (Sandbox Code Playgroud) globToRegex' (c:cs) = escape c ++ globToRegex' cs
Run Code Online (Sandbox Code Playgroud)
这个函数不是尾递归的,它说答案依赖于Haskell非严格(懒惰)评估策略.该(++)运营商的简单定义在于以下这不是尾递归.
Run Code Online (Sandbox Code Playgroud)(++) :: [a] -> [a] -> [a] (x:xs) ++ ys = x : (xs ++ ys) [] ++ ys = ys在严格的语言中,如果我们评估
"foo" ++ "bar",则构造整个列表,然后返回.非严格评估在需要之前将大部分工作推迟.如果我们要求表达式的元素,
"foo" ++ "bar"函数定义的第一个模式匹配,我们返回表达式x : (xs ++ ys).因为(:)构造函数是非严格的,所以xs ++ ys可以推迟评估:我们生成更多的结果元素,无论它们需要什么速率.当我们生成更多结果时,我们将不再使用x,因此垃圾收集器可以回收它.由于我们按需生成结果元素,并且不保留我们完成的部分,因此编译器可以在恒定空间中评估我们的代码.
(重点补充.)
上面粗体的解释对Haskell来说是必不可少的,但是
x:(xs ++ ys)会在恒定的空间中评估",怎么样?这听起来像尾递归一样!例如,在Vim中,^可以将光标移动到该行的第一个单词(非空白空间)
The quick brown fox jumps over the lazy dog
这里^的Vim将移动到T的The,但是在Emacs中,如何将光标移动到该行的第一个单词(非空白空间)而不是使用一系列Mb/f和Ca/e/b/f?是否有现成的命令来制作它?
谢谢