发生检查:无法构造无限类型:t~ [t]

时间:2015-07-01 21:02:46

标签: haskell

我开始学习Haskell。我正在尝试运行此代码

-- Helpers.hs
module Helpers
where

lst1 +++ lst2 = if null lst1
            then lst2
            else (head lst1) : (tail lst1 +++ lst2)


reverse2 lst = if null lst
           then []
           else reverse2 (tail lst) : (head lst)
-- Main.hs
import Helpers

main :: IO ()
main = putStrLn . reverse2 [2, 8, 7]

我收到此错误:

D:\Haskell\project>cabal configure
Resolving dependencies...
Configuring one-0.1.0.0...

D:\Haskell\project>cabal build
Building one-0.1.0.0...
Preprocessing executable 'one' for one-0.1.0.0...
[1 of 2] Compiling Helpers          ( src\Utils\Helpers.hs, dist\build\one\one-t
mp\Helpers.o )

src\Utils\Helpers.hs:11:21:
    Occurs check: cannot construct the infinite type: t ~ [t]
    Relevant bindings include
      lst :: [[t]] (bound at src\Utils\Helpers.hs:9:10)
      reverse2 :: [[t]] -> [t] (bound at src\Utils\Helpers.hs:9:1)
    In the first argument of `(:)', namely `reverse2 (tail lst)'
    In the expression: reverse2 (tail lst) : (head lst)

我该如何解决?

4 个答案:

答案 0 :(得分:7)

reverse2 (tail lst)的类型为[a],而head lst的类型为a。同时,:运算符的类型为a -> [a] -> [a]。当您尝试reverse2 (tail lst) : (head lst)时,Haskell认为head lst是一个列表,其元素与reverse2 (tail lst)的类型相同 - 即head lst :: [[a]]。但是,head lst的类型必须与reverse2 (tail lst)的元素相同,这意味着reverse2 (tail lst) :: [[[a]]],但head lst必须为[[[[a]]]],然后{ {1}}必须是reverse2 (tail lst)类型,我认为你可以看到它的发展方向。

发生此问题是因为您未正确使用[[[[[a]]]]]。如果要将元素追加到列表中,最简单的方法是:

答案 1 :(得分:3)

所以直接的问题是你将错误类型的参数传递给:运算符,并且haskell试图使它们成为正确的类型,并且努力使它们成为正确的类型正确的类型会导致模糊的错误消息。

作为一般策略,当出现如此奇怪的错误消息时,我开始将类型签名应用于它所抱怨的内容,以便haskell不会尝试推断远离我的意图的类型签名。

使用您的代码执行此操作,我首先将其添加到reverse2

reverse2 :: [t] -> [t]
reverse2 lst = if null lst
           then []
           else reverse2 (tail lst) : (head lst)

这会将错误消息更改为:

Couldn't match expected type ‘t’ with actual type ‘[t]’
      ‘t’ is a rigid type variable bound by
          the type signature for reverse2 :: [t] -> [t]
          at /tmp/flycheck-stackov.hs:6:13
    Relevant bindings include
      lst :: [t] (bound at /tmp/flycheck-stackov.hs:7:10)
      reverse2 :: [t] -> [t] (bound at /tmp/flycheck-stackov.hs:7:1)
    In the first argument of ‘(:)’, namely ‘reverse2 (tail lst)’
    In the expression: reverse2 (tail lst) : (head lst)

好的,现在它说"我期待类型t,但在查看[t]"的第一个参数时得到类型:。 / p>

事实上,如果我们问ghci :的类型是什么,我们会看到:

Prelude> :t (:)
(:) :: a -> [a] -> [a]

因此:的左参数需要是单个项,右参数是列表。您在左侧使用了一个列表,在右侧使用了一个项目。

要连接您想要的方式,另一个答案说您应该使用++

reverse2 :: [t] -> [t]
reverse2 lst = if null lst
           then []
           else reverse2 (tail lst) ++ [head lst]

(此外,您在main例程中遇到类型错误。您想说putStrLn $ reverse2 [2, 8, 7]而不是putStrLn . reverse2 [2, 8, 7]

答案 2 :(得分:1)

您应该可以通过以下方式修复它:

reverse2 lst = if null lst
   then []
   else reverse2 (tail lst) ++ [head lst]

@jwodder已经解释了更多的理论原因,这不起作用。

请注意,上述实现效率很低,因为++完全遍历其第一个参数并在之后进行连接。

更复杂的方法如下

reverse3 lst = 
    let aux lst acc = if null lst then acc else aux (tail lst) (head lst : acc) 
    in aux lst []

明确注释类型通常很有帮助(即您编写reverse2 :: [a] -> [a]

答案 3 :(得分:0)

正如扩展jwodder所写内容的注释一样,如果您明确键入内容,则可以获得更有用的错误消息:

Prelude> let reverse2 :: [a] -> [a]; reverse2 lst = if null lst then [] else (reverse2 (tail lst)) : (head lst)

<interactive>:6:70:
    Couldn't match expected type ‘a’ with actual type ‘[a]’
      ‘a’ is a rigid type variable bound by
          the type signature for reverse2 :: [a] -> [a] at <interactive>:6:17
    Relevant bindings include
      lst :: [a] (bound at <interactive>:6:38)
      reverse2 :: [a] -> [a] (bound at <interactive>:6:29)
    In the first argument of ‘(:)’, namely ‘(reverse2 (tail lst))’
    In the expression: (reverse2 (tail lst)) : (head lst)