我正在尝试编写一个函数,该函数接受一个字符串并返回没有空格字符的原始字符串作为字符串列表,例如 toStrings"感谢您的帮助" - > ["感谢","对于","您的","帮助"]。
我想使用累加器来解决这个问题,所以我做了以下几点:
toStrings :: String -> [String]
toStrings str = go str []
where
go str acc
| str == [] = acc
| otherwise = go (dropWhile (/=' ') str) acc : (takeWhile (/=' ') str)
它不起作用。编译器说:
Couldn't match type '[Char]' with 'Char'
我以为我在和弦乐队合作。 非常感谢帮助。
谢谢Eitan
答案 0 :(得分:6)
takeWhile
上的 String
将返回String
。因此,你有
go (…) acc : takeWhile (…)
后者是String
。但是,此时您需要[String]
。自String = [Char]
起,我们遇到以下类型不匹配:
String = [Char] -- actual
[String] = [[Char]] -- expected
然后GHC会看到[[Char]]
和[Char]
,删除一个列表图层,然后看到[Char]
和Char
,它们不再被简化了。
这就是你收到错误的原因。在错误消息中键入同义词和简化类型。
话虽如此,你永远不会改变acc
,也不会在之后删除空格。因此,您当前的实现将无限循环。
我建议你在没有累加器的情况下解决这个问题,而是尝试提出与
类似的东西-- pseudo code
go str = firstWord str : go (restOfString str)
请注意,firstWord
应该删除前导空格,否则最终会出现无限循环。
答案 1 :(得分:5)
我认为如果将类型添加到go
函数会有帮助。根据功能描述,它应该是:
toStrings :: String -> [String]
toStrings str = go str []
where
go str acc :: String -> [String] -> [String]
| str == [] = acc
| otherwise = go (dropWhile (/=' ') str) acc : (takeWhile (/=' ') str)
但在您的递归通话中,您拨打(go somestr acc) : someotherstr
(我这里使用somestr
和someotherstr
,以便更容易理解为什么它不起作用)。这不符合,因为go somestr acc
会产生[String]
(给定有效),someotherstr
是String
。如果你使用缺点(:)
,它希望头部(左操作数)为String
,尾部(右操作数)为[String]
。
但实际上我们根本不需要使用累加器。我们可以构造一个“cons”并在尾部执行递归,如:
toStrings :: String -> [String]
toStrings ss | null s1 = []
| otherwise = word : toStrings rest
where s1 = dropWhile (== ' ') ss
(word, rest) = span (/= ' ') s1
首先,我们删除字符串ss
的所有空格,然后是s1
。如果s1
是空列表,那么我们就完成了,我们返回空列表。否则,我们执行span
(条件分割),以便我们获得一个元组,其中单词作为第一个项目,其余的字符串作为第二个项目。然后我们生成word
,并在rest
上执行递归。