Haskell Newbie-发生检查:无法构造无限类型:a~[a]

Haskell Newbie-发生检查:无法构造无限类型:a~[a],haskell,Haskell,我试图使一个函数“tokenize”包含3个参数;主字符串、应该在自己的字符串中的字符字符串以及要从字符串中删除的字符字符串 tokenize :: String -> String -> String -> [String] tokenize [] imp remm = [] tokenize str imp remm = let chr = (head str) in if elem chr imp then ([ch

我试图使一个函数“tokenize”包含3个参数;主字符串、应该在自己的字符串中的字符字符串以及要从字符串中删除的字符字符串

tokenize :: String -> String -> String -> [String]
tokenize [] imp remm = []
tokenize str imp remm =   let chr = (head str) in
                          if elem chr imp then ([chr] : (tokenize (tail str) imp remm))
                          else if (elem chr  remm ) then (tokenize (tail str) imp remm)
                          else chr: (tokenize (tail str) imp remm)
我收到以下错误消息:

Occurs check: 
cannot construct the infinite type: a ~ [a]
Expected type: [a]
Actual type: [[a]]

在表达式中,使用两个子表达式:

[chr] : (tokenize (tail str) imp remm))

这两者不能相互协调,因为这意味着
[chr]
chr
具有相同的类型,因此会出现错误

通常在函数式编程中,参数以不同的顺序写入。实际上,将其写成
tokenize imp remm str
更为合理,其中包含
imp
重要字符、
remm
要删除的字符和
str
要处理的字符串

我们可以使用助手函数
go
来实现该功能。此处 GO 基本上应考虑四种情况:

  • 我们到达了列表的末尾,因此返回一个带有空列表的单例列表
  • 第一个字符是要从输出中消除的,我们在字符串的尾部递归
  • 字符很重要,我们生成一个空列表,字符包装在一个列表中,并在尾部递归;及
  • 如果以上所有内容都不适用,我们将在递归时将字符前置到我们检索的列表的头部
  • 我们过滤掉空列表,例如当我们在
    imp
    中有两个连续字符时,可能会出现空列表

    例如:

    tokenize :: [Char] -> [Char] -> String -> [String]
    tokenize imp remm = filter (not . null) . go
        where go [] = [[]]
              go (x:xs) | elem x remm = go xs
                        | elem x imp = [] : [x] : go xs
                        | otherwise = let (y:ys) = go xs in (x:y) : ys
    然后我们得出:

    Prelude> tokenize "abc" "def" "defaabyesays"
    ["a","a","b","ys","a","ys"]
    

    但是,使用separte函数解决单独的问题可能更好。例如,首先有一个从
    remm
    等中删除字符的函数。这使函数更容易理解和修复错误。

    在表达式中,使用两个子表达式:

    [chr] : (tokenize (tail str) imp remm))
    

    这两者不能相互协调,因为这意味着
    [chr]
    chr
    具有相同的类型,因此会出现错误

    通常在函数式编程中,参数以不同的顺序写入。实际上,将其写成
    tokenize imp remm str
    更为合理,其中包含
    imp
    重要字符、
    remm
    要删除的字符和
    str
    要处理的字符串

    我们可以使用助手函数
    go
    来实现该功能。此处 GO 基本上应考虑四种情况:

  • 我们到达了列表的末尾,因此返回一个带有空列表的单例列表
  • 第一个字符是要从输出中消除的,我们在字符串的尾部递归
  • 字符很重要,我们生成一个空列表,字符包装在一个列表中,并在尾部递归;及
  • 如果以上所有内容都不适用,我们将在递归时将字符前置到我们检索的列表的头部
  • 我们过滤掉空列表,例如当我们在
    imp
    中有两个连续字符时,可能会出现空列表

    例如:

    tokenize :: [Char] -> [Char] -> String -> [String]
    tokenize imp remm = filter (not . null) . go
        where go [] = [[]]
              go (x:xs) | elem x remm = go xs
                        | elem x imp = [] : [x] : go xs
                        | otherwise = let (y:ys) = go xs in (x:y) : ys
    然后我们得出:

    Prelude> tokenize "abc" "def" "defaabyesays"
    ["a","a","b","ys","a","ys"]
    

    但是,使用separte函数解决单独的问题可能更好。例如,首先有一个从
    remm
    中删除字符的函数,等等。这使您的函数更容易理解和修复错误。

    [chr]:tokenize
    是罪魁祸首,但也就是说,这看起来太复杂了。是的,我想。这是我第一次尝试函数式编程,所以我还不太习惯。问题是,如果我去掉括号,我就不会在它们自己的列表中得到imp元素:“‘标记化’的类型是什么?”?如果你给它一个类型定义,你通常会得到一个更有用的错误消息。哦,对不起,我要添加那个!这可能是因为,在一个地方你说
    [chr]:tokenize
    ,然后你说
    chr:tokenize
    [chr]:tokenize
    是罪魁祸首,但话说回来,这看起来太复杂了。是的,我想。这是我第一次尝试函数式编程,所以我还不太习惯。问题是,如果我去掉括号,我就不会在它们自己的列表中得到imp元素:“‘标记化’的类型是什么?”?如果你给它一个类型定义,你通常会得到一个更有用的错误消息。哦,对不起,我要添加那个!这可能是因为在一个地方你说
    [chr]:tokenize
    ,然后你说
    chr:tokenize