我如何在haskell中的空格后分割字符串?

时间:2018-11-24 18:35:19

标签: string haskell recursion

我知道Haskell没有循环,所以我不能这样做。我也知道递归在这里是“有用的”,但这就是我所知道的全部。 到目前为止,我已经获得了一个基本的类型签名,即

toSplit :: String -> [String]

基本上,它从字符串变成单词列表...

谢谢!

P.S。我想使用takeWhiledropWhile函数...而不是库...

2 个答案:

答案 0 :(得分:3)

如果您想自己实现,那么要做的第一件事就是找到第一个单词。 您可以执行以下操作:

takeWhile (/=' ') s

如果字符串以定界字符开头,则需要先修剪它们。我们可以使用dropWhile来做到这一点。

takeWhile (/=' ') $ dropWhile (==' ') s

现在我们有了第一个单词,但是我们还需要从第一个单词开始的字符串的其余部分,然后在该字符串上递归。我们可以使用splitAt

(_, rest) = splitAt (length word) s

然后我们使用字符串的rest进行递归,并将第一个单词限制在该递归的结果上,从而为我们提供所有单词的列表。

我们需要定义一个基本情况,即空字符串的结果,一旦没有更多字符,该结果将终止递归。

toSplit :: String -> [String]
toSplit "" = []
toSplit s =
  let word = takeWhile (/=' ') $ dropWhile (==' ') s
      (_, rest) = splitAt (length word) s
  in word : toSplit (dropWhile (==' ') rest)

编辑:上面的代码中有一个错误,它不能正确处理边缘情况。

错误是它在原始s上调用splitAt,但是如果s有前导空格,则会给出错误的结果:

*Main> toSplit " foo"
["foo","o"]

这应该修复该错误:

let trimmed = dropWhile (==' ') s
    word = takeWhile (/=' ') trimmed
    (_, rest) = splitAt (length word) trimmed

剩下一个极端的情况:

*Main> toSplit " "
[""]

一种可能的解决方案是使用辅助函数:

toSplit :: String -> [String]
toSplit = splitWords . dropWhile (==' ') 
    where
        splitWords "" = []
        splitWords s = 
          let word = takeWhile (/=' ') s
              (_, rest) = splitAt (length word) s
          in word : splitWords (dropWhile (==' ') rest)

答案 1 :(得分:1)

  

我知道Haskell没有循环,所以我不能这样做。我也知道   递归在这里“很有帮助” ...

,Haskell使用递归而不是命令式语言中的forwhile循环结构。

代替我自己编写递归函数,更常见的用法是mapfoldr (foldl)unfoldr等递归遍历列表。这些功能的优点是您可以将要执行的操作集中在step函数中。像您的问题一样,适合使用unfoldr来完成它。

以下是takeWhiledropWhile的示例:

import Data.Char (isSpace)
import Data.List (unfoldr)

toSplit::String->[String]
toSplit = unfoldr step 
    where step [] = Nothing
          step xs = Just (takeWhile (not . isSpace) xs, 
                          (dropWhile isSpace . dropWhile (not . isSpace)) xs) 

但是有点冗长,使用break函数可能更易读,例如:

toSplit' = unfoldr step
    where step [] = Nothing
          step xs = let (word, rest) = break isSpace xs
                    in  Just (word, dropWhile isSpace rest)