我有以下作业:


Examples:

split '#' "foo##goo" = ["foo","","goo"]
split '#' "#" = ["",""]

我编写了以下函数:
split :: Char -> String -> [String]
split c "" = [""]
split a "a" = ["",""]
split c st =  takeWhile (/=c) st : split c tail((dropWhile (/=c) st))

它不能编译,我不明白为什么。
TakeWhile 将所有不是 c 的字符添加到结果中,然后 tail 删除已经找到的 c,我们递归地将 split 应用于字符串的其余部分,通过 dropWhile 获得。 : 应该制作一个“列表”列表,因为字符串是 Haskell 中的字符列表。我的思想差距在哪里?

更新:

我已将我的程序更新为以下内容:
my_tail :: [a]->[a]
my_tail [] = []
my_tail xs = tail xs

split :: Char -> String -> [String]
split c "" = [""]
split a "a" = ["",""]
split c st =  takeWhile (/=c) st ++ split c (my_tail(dropWhile (/=c) st))

我仍然收到错误消息,如下所示:
list - 在 Haskell 中使用分隔字符将字符串分成更多部分-LMLPHP

为什么是预期的类型 [String] 然后是 [Char]?

最佳答案

这不编译的原因是因为 Haskell 将您的最后一个子句视为:

split c st = takeWhile (/=c) st : split c tail ((dropWhile (/=c) st))

因此,它认为您将三个参数应用于 split : ctail((dropWhile (/=c) st)) 。您应该在这里使用括号,例如:
split c st = takeWhile (/=c) st : split c (tail (dropWhile (/=c) st))

但这并不能完全解决问题。例如,如果我们尝试运行您的测试用例,我们会看到:
Prelude> split '#' "foo##goo"
["foo","","goo"*** Exception: Prelude.tail: empty list

tail :: [a] -> [a] 是一个“非总”函数。对于空列表,tail 会出错。确实:
Prelude> tail []
*** Exception: Prelude.tail: empty list

最终,列表将用完字符,然后 tail 将引发错误。我们可能想在这里使用 span :: (a -> Bool) -> [a] -> ([a], [a]) ,并使用模式匹配来确定是否还有一些元素需要处理,例如:
split :: Eq a => a -> [a] -> [[a]]
split _ [] = [[]]
split c txt = pf : rst
    where rst | (_:sf1) <- sf = split c sf1
              | otherwise = []
          (pf,sf) = span (c /=) txt

这里 span (c /=) txt 将因此将非空列表 txt 分成两部分 pf (前缀)是不等于 c 的项目的最长前缀。 sf(后缀)是剩下的元素。

无论 sf 是否为空,我们都会发出前缀 pf 。然后我们检查后缀。我们知道要么 sf 为空(我们到达了列表的末尾),要么 sf 的第一个元素等于 c 。因此,我们使用模式保护来检查这是否与 (_:sf1) 模式匹配。如果 sf 非空,就会发生这种情况。在这种情况下,我们将 sf1sf 的尾部绑定(bind),然后在尾部进行递归。如果 sf1 为空,我们可以停止,从而返回 []

例如:
Prelude> split '#' "foo##goo"
["foo","","goo"]
Prelude> split '#' "#"
["",""]

关于list - 在 Haskell 中使用分隔字符将字符串分成更多部分,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56672750/

10-12 23:58