我开始学习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)
我该如何解决?
答案 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)