Cla*_*orm 0 string recursion haskell
我知道 Haskell 没有循环,所以我不能那样做。我也知道递归在这里是“有用的”,但这就是我所知道的。到目前为止,我已经获得了一个基本的类型签名,即
toSplit :: String -> [String]
Run Code Online (Sandbox Code Playgroud)
基本上,它从一个字符串变成了一个单词列表......
谢谢!
PS我想使用takeWhile和dropWhile功能......不是图书馆......
如果你想自己实现它,你需要做的第一件事就是找到第一个词。你可以这样做:
takeWhile (/=' ') s
Run Code Online (Sandbox Code Playgroud)
如果字符串以分隔符开头,则需要先修剪这些字符。我们可以用dropWhile.
takeWhile (/=' ') $ dropWhile (==' ') s
Run Code Online (Sandbox Code Playgroud)
现在我们有了第一个单词,但我们还需要从第一个单词开始的字符串的其余部分,我们将在其上递归。我们可以使用splitAt:
(_, rest) = splitAt (length word) s
Run Code Online (Sandbox Code Playgroud)
然后我们rest对字符串的 进行递归,并将第一个单词 cons 到该递归的结果上,从而为我们提供所有单词的列表。
我们需要定义基本情况,即空字符串的结果,一旦没有更多字符,它将终止递归。
toSplit :: String -> [String]
toSplit "" = []
toSplit s =
let word = takeWhile (/=' ') $ dropWhile (==' ') s
(_, rest) = splitAt (length word) s
in word : toSplit (dropWhile (==' ') rest)
Run Code Online (Sandbox Code Playgroud)
编辑:上面的代码中有一个错误,它没有正确处理边缘情况。
错误在于它在原始文件上调用 splitAt ,s但如果s有前导空格,则会产生错误的结果:
*Main> toSplit " foo"
["foo","o"]
Run Code Online (Sandbox Code Playgroud)
这应该修复错误:
let trimmed = dropWhile (==' ') s
word = takeWhile (/=' ') trimmed
(_, rest) = splitAt (length word) trimmed
Run Code Online (Sandbox Code Playgroud)
这留下了一个边缘情况:
*Main> toSplit " "
[""]
Run Code Online (Sandbox Code Playgroud)
一种可能的解决方案是使用辅助函数:
toSplit :: String -> [String]
toSplit = splitWords . dropWhile (==' ')
where
splitWords "" = []
splitWords s =
let word = takeWhile (/=' ') s
(_, rest) = splitAt (length word) s
in word : splitWords (dropWhile (==' ') rest)
Run Code Online (Sandbox Code Playgroud)