当尝试使用foldr实现dropWhile时,我想到的第一个算法如下:
dropWhile' :: (a -> Bool) -> [a] -> [a]
dropWhile' pred = fst . foldr (\cur (acc, xs) ->
if pred cur
then (acc, cur:xs)
else (cur:xs, cur:xs)) ([], [])
虽然这个方法能够运行,但是当输入无限长的列表时会导致栈溢出而没有返回任何值。因为我不确定为什么它不能正常工作,所以我只是试着调整了函数,直到得出这个结果:
dropWhile' :: (a -> Bool) -> [a] -> [a]
dropWhile' pred = fst . foldr (\cur t -> let (acc, xs) = t in
if pred cur
then (acc, cur:xs)
else (cur:xs, cur:xs)) ([], [])
如您所见,这个函数和第一个函数唯一的区别在于,我在 let
绑定内部解构了元组 (acc, xs)
,而不是直接在函数参数中解构。出于某种奇怪的原因,这段代码可以处理无限长的列表。
如果有人知道为什么会这样,请告诉我。
~
来显式地延迟lambda的模式,并获得两个世界的最佳效果(在无限列表上让let
表现良好,lambda的美学更好)。\cur ~(acc, xs) -> if ...
- Daniel Wagner