Haskell 单词实现

Haskell words implementation

我尝试从 Data.List 实现 words 函数,但我的实现并没有完全按照我的意愿工作。

例如,如果函数的输入是"tere vana kere",那么输出是["vana", "kere"],它会遗漏第一个单词。但是当我在我的输入前面添加空格 "tere vana kere" 那么输出是正确的 ["tere", "vana", "kere"]

谁能指出问题所在。
谢谢

1
2
3
4
5
6
7
8
9
words' :: String -> [String]
words' xs = snd $ foldr (\\x acc -> if isSpace x then
                                    if null (fst acc) then
                                        acc
                                    else
                                        ([], (fst acc): (snd acc))
                               else
                                     (x:fst acc, snd acc)  
                               ) ([],[]) xs

好的,让我们试试这个:

1
2
3
4
5
6
7
8
9
step x acc =
  if isSpace x
    then
      if null (fst acc)
        then acc
        else ([], (fst acc) : (snd acc))
    else (x : fst acc, snd acc)

words' xs = snd $ foldr step ([], []) xs

现在让我们一步一步来:假设我们想要 words'"ABC DEF GHI"。我们可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Prelude> step 'I' ([], [])
("I", [])
Prelude> step 'H' it
("HI", [])
Prelude> step 'G' it
("GHI", [])
Prelude> step ' ' it
("", ["GHI"])
Prelude> step 'F' it
("F", ["GHI"])
Prelude> step 'E' it
("EF", ["GHI"])
Prelude> step 'D' it
("DEF", ["GHI"])
Prelude> step ' ' it
("", ["DEF","GHI"])
Prelude> step 'C' it
("C", ["DEF","GHI"])
Prelude> step 'B' it
("BC", ["DEF","GHI"])
Prelude> step 'A' it
("ABC", ["DEF","GHI"])
Prelude> snd it
["DEF","GHI"]

你看到这里的问题了吗?

问题是,当您看到空格字符时,您只会将当前单词"刷新"到单词列表中。特别是,当您看到输入结束时,您不会刷新。您可以通过替换 snd:

来解决此问题

1
words' xs = (\\ (w, ws) -> w:ws) $ foldr step ([], []) xs

顺便说一句,恭喜您使代码正确处理多个连续空格。 :-)

编辑:为了保留这个不错的属性:

1
words' xs = (\\ (w, ws) -> if null w then ws else w:ws) $ ...


初学者haskeller的一个不起眼的选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import           Data.Char     (isSpace)

firstWord :: String -> String
firstWord s =
  if isSpace $ head s
    then getFirstWord $ tail s
    else getFirstWord s
  where
    getFirstWord = takeWhile (/= ' ')

words' :: String -> [String]
words' s
  | null s = []
  | otherwise = first : words' rest
  where
    first = firstWord s
    rest = drop (length first + 1) s

写上面的答案:
与其在字符串末尾使用单独的检查刷新当前单词,不如在字符串开头添加一个空格。

1
2
3
4
5
6
7
8
9
step x acc =
  if isSpace x
    then
      if null (fst acc)
        then acc
        else ([], (fst acc) : (snd acc))
    else (x : fst acc, snd acc)

words' xs = snd $ foldr step ([], []) $ ' ':xs