用折叠实现takeWhile

Amo*_*moz 3 haskell

如何使用fold在Haskell中实现takeWhile函数?

takeWhile :: (a -> Bool) -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)

我尝试了类似于实现这样的过滤器的策略

filter :: (a -> Bool) -> [a] -> [a]
filter f = foldr (\x acc -> if f x then x : acc else acc) []
Run Code Online (Sandbox Code Playgroud)

但是当fx是假的时候我怎么能停下来?

Jon*_*rdy 9

只要改变acc[]else分支:

takeWhile f = foldr (\x acc -> if f x then x : acc else []) []
Run Code Online (Sandbox Code Playgroud)

这个想法是你在使用输入列表中的元素时懒得构建结果列表,因此[]当你想终止结果列表时返回.

takeWhile (< 3) [0..]
=
0 : takeWhile (< 3) [1..]
=
0 : 1 : takeWhile (< 3) [2..]
=
0 : 1 : 2 : takeWhile (< 3) [3..]
=
0 : 1 : 2 : []
=
[0, 1, 2]
Run Code Online (Sandbox Code Playgroud)

这也说明了Haskell列表是如何真正的值.右侧折叠是小型状态机,它们逐步移动输入流以生成输出流.