Real World Haskell, chapter 4, page 98 of the printed version问能否使用折叠实现words
函数,这也是我的问题:
是否可能?如果不能,为什么?如果可以,如何实现?
我想到了以下实现方法,其基本思路是将每个非空格字符前置到输出列表中的最后一个单词上(在otherwise
语句块中完成),如果没有空单词则使用空格触发将空单词添加到输出列表中(在if
-then
-else
语句块中完成)。
myWords :: String -> [String]
myWords = foldr step [[]]
where
step x yss@(y:ys)
| x == ' ' = if y == "" then yss else "":yss
| otherwise = (x:y):ys
显然,这个解决方案是错误的,因为输入字符串中的前导空格会导致输出字符串列表中有一个前导空字符串。
在上面的链接中,我研究了其他读者提出的几种解决方案,其中许多解决方案与我的解决方案类似,但它们通常通过“后处理”折叠的输出来进行,例如如果存在一个空的前导字符串,则通过tail
将其删除。
其他方法使用元组(实际上只是一对),因此折叠处理该对并且可以很好地处理前导/尾随空格。
在所有这些方法中,foldr
(或另一个折叠函数)不是直接提供最终输出的函数;总是有其他东西必须以某种方式调整输出。
因此,我回到最初的问题,并问是否实际上可以使用折叠来实现words
(以正确处理尾随/前导/重复空格的方式)。通过使用折叠,我的意思是折叠函数必须是最外层的函数:
myWords :: String -> [String]
myWords input = foldr step seed input
["xa"] == words "xa" == step 'x' (words "a") == step 'x' (words " a") == words "x a" == ["x", "a"]
,这样做的好处是可以作为fold函数的任何方向的有效参数。 - Cireo