首页 > 解决方案 > Haskell Newbie - 发生检查:无法构造无限类型:a ~ [a]

问题描述

我正在尝试制作一个带有 3 个参数的函数“tokenize”;主字符串,应该在自己的字符串中的字符字符串和要从字符串中删除的字符字符串。

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]]

标签: haskell

解决方案


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

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

chr: (tokenize (tail str) imp remm)

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

通常在函数式编程中,参数以不同的顺序写入。tokenize imp remm str确实,将其与imp重要字符、remm要删除的字符和要处理的字符串一起编写更有意义str

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

  1. 我们到达列表的末尾,因此返回一个带有空列表的单例列表;
  2. 第一个字符是要从输出中消除的东西,我们在字符串的尾部递归;
  3. 字符很重要,我们产生一个空列表,将字符包裹在列表中,并在尾部递归;和
  4. 如果以上所有内容都不适用,我们将在递归时将字符添加到我们检索到的列表的头部。

我们过滤掉空列表,例如当我们有两个连续的字符时可能会发生这种情况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"]

然而,通过单独的功能解决单独的问题可能会更好。例如,首先有一个从remm等中删除字符的功能。这使您更容易理解和修复您的功能。


推荐阅读