Haskell - 无法将类型`[Char]'与`Char'匹配

Ell*_*ith 4 haskell

我目前在Haskell中有以下代码

splitStringOnDelimeter :: String -> Char -> [String]

splitStringOnDelimeter "" delimeter = return [""]

splitStringOnDelimeter string delimeter = do
    let split = splitStringOnDelimeter (tail string) delimeter
    if head string == delimeter
    then return ([""] ++ split)
    else return ( [( [(head string)] ++ (head split) )] ++ (tail split))
Run Code Online (Sandbox Code Playgroud)

如果我运行它在Haskell的终端(即https://www.tryhaskell.org与如return语句值)( [( [(head "ZZZZ")] ++ (head ["first", "second", "third"]) )] ++ (tail ["first", "second", "third"]))[""] ++ ["first", "second", "third"][""]后来我从哪个是我的本地栈编译器是不同的终端接收到正确的类型.此外,如果我也将顶部return语句更改为return ""then那么它不会抱怨我非常确定不正确的语句.

我的本地编译器可以正常使用我的Haskell代码库的其余部分,这就是为什么我认为我的代码可能有问题...

Wil*_*sem 12

Monad类型类设计中不幸的一件事就是它们引入了一个叫做的函数return.但是,虽然在许多命令式编程语言中return都是返回内容的关键字,但在Haskell中return有一个完全不同的含义,它并没有真正返回一些东西.

您可以通过删除以下内容来解决问题return:

splitStringOnDelimeter :: String -> Char -> [String]
splitStringOnDelimeter "" delimeter = [""]
splitStringOnDelimeter string delimeter =
    let split = splitStringOnDelimeter (tail string) delimeter in
    if head string == delimeter
    then ([""] ++ split)
    else ( [( [(head string)] ++ (head split) )] ++ (tail split))
Run Code Online (Sandbox Code Playgroud)

return :: Monad m => a -> m a用于包装(的类型的值a在一个单子).由于这里有关于列表的签名提示,Haskell将假设您查找列表monad.所以这意味着你return将包装[""]到另一个列表中,所以return [""]你可能会隐式写入(在此上下文中),[[""]]这当然与之匹配[String].

同样的do,你再次制作一个monadic函数,但是这里你的函数与monad没什么关系.

请注意,名称本身return并不坏,但由于几乎所有命令式语言都附加了(几乎)等同的含义,因此大多数人认为它在函数式语言中的工作方式相同,但事实并非如此.

请注意,您使用的函数如head,tail等.这些通常被视为反模式:您可以使用模式匹配.我们可以将其重写为:

splitStringOnDelimeter :: String -> Char -> [String]
splitStringOnDelimeter "" delimeter = [""]
splitStringOnDelimeter (h:t) delimeter | h == delimeter = "" : split
                                       | otherwise = (h : sh) : st
    where split@(sh:st) = splitStringOnDelimeter t delimeter
Run Code Online (Sandbox Code Playgroud)

通过使用模式匹配,我们确信它string有一个头部h和一个尾部t,我们可以直接将它们用于表达式.这使得表达式更短,更易读.虽然if- then- else条款本身并不反模式,但我个人认为警卫在语法上更干净.因此where,我们在这里使用一个子句来调用splitStringOnDelimter t delimeter,并且我们将它与模式匹配split(以及与之相符(sh:st).我们知道这将始终匹配,因为基本案例和归纳案例总是产生一个至少包含一个元素的列表.允许使用写一个整洁的表现,我们可以使用shst直接,而不是调用headtail.

如果我在本地测试这个功能,我得到:

Prelude> splitStringOnDelimeter "foo!bar!!qux" '!'
["foo","bar","","qux"]
Run Code Online (Sandbox Code Playgroud)

作为外卖消息,我认为你最好避免使用return,do除非你知道这个函数和关键字(do是一个关键字)的真正含义.在函数式编程的上下文中,它们具有不同的含义.

  • 与此同时,我开始推荐的(对于拥有足够新版本的`ghc`的人来说)就是永远不会使用`return`,当你确实需要一个monadic单元时,使用`pure`,在没有不幸的命名含义的情况下做同样的事情. (5认同)