本周末我一直在尝试学习Haskell,而且当我真正尝试编写递归函数(而不是仅仅从教程中输入一个)时,我得到了一个类型错误。
我非常感谢任何帮助理解(1)错误意味着什么(我不理解“修复”); (2)为什么会抛出错误 - 我很确定我没有对传递的类型犯任何错误。
我的代码:
tell :: (Show a) => [a] -> String
tell'in :: (Show a, Num n) => [a] -> n -> String -> (n, String)
tell [] = "The list is empty"
tell (x:[]) = "The list has one element: " ++ show x
tell (x:xs) = "The list has " ++ n ++ " elements: " ++ s where (n, s) = (tell'in (xs) (1) (show x))
tell'in (x:[]) n s = ((n + 1), (s ++ " and " ++ (show x)))
tell'in (x:xs) n s = tell'in xs (n+1) (s ++ " and " ++ show x)
当我尝试将其加载到GHCI中时出现的错误:
[1 of 1] Compiling Main ( example.hs, interpreted )
example.hs:13:88:
Could not deduce (Num [Char]) arising from the literal `1'
from the context (Show a)
bound by the type signature for tell :: Show a => [a] -> String
at example.hs:(11,1)-(13,99)
Possible fix:
add (Num [Char]) to the context of
the type signature for tell :: Show a => [a] -> String
or add an instance declaration for (Num [Char])
In the second argument of `tell'in', namely `(1)'
In the expression: (tell'in (xs) (1) (show x))
In a pattern binding: (n, s) = (tell'in (xs) (1) (show x))
Failed, modules loaded: none.
Prelude>
答案 0 :(得分:3)
tell'in
正在返回Num n => n
,然后您(++)
String
(又名[Char]
)在{{1}的最后一个等式中tell
}}。您可能希望在那里使用show n
而不是n
。
答案 1 :(得分:2)
tell'in
的类型表示其返回值的第一个坐标与第二个参数的类型相同。在tell
中,您使用数字作为其第二个参数(tell'in
)调用1
,然后使用其返回值的第一个坐标(n
)作为字符串通过将其附加到其他字符串。所以无论这种类型是什么,它必须同时是一个字符串和一个数字。该错误告诉您,字符串([Char]
)无法被视为一种数字,当它试图解释数字文字1
的含义时会出现这种情况。你可能意味着
"The list has " ++ show n ++ " elements: " ++ ...
答案 2 :(得分:1)
有一个通用的方案来理解编译错误,如果它是某种类型不匹配: 您需要提供更具体的类型注释以缩小错误!
tell'in
和tell
已有类型:
tell :: (Show a) => [a] -> String
tell'in :: (Show a, Num n) => [a] -> n -> String -> (n, String)
所以,你改变了这个:
tell (x:xs) = "The list has " ++ n ++ " elements: " ++ s
where (n, s) = tell'in (xs) (1) (show x))
对此:
-- vvvvvvvvvvvvvvvvvvvvvvv vvvvvvvv
tell ((x:xs)::(Show a=>[a])) = "The list has " ++ (n::Int) ++ " elements: " ++ s
where (n::Int, s::String) = tell'in (xs) (1::Int) (show x))
-- ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^
现在,您已经看到错误,或者您尝试再次编译并有更具体的错误消息。
无论如何,最好使用::Int
代替::Num n=>n
,因为只要未指定确切类型,后者就会推广到::Integer
。 Int
不大于一个机器字(32/64位),因此它比任意大小的Integer
更快。