我一周前开始学习Haskell并且有一个奇怪的问题。我创建了一个简单的数据类型,并希望在控制台中显示它。我为我的类型的2个构造函数创建了2个函数。如果我使用带有2个参数的构造函数,编译器可以调用函数。但它不能调用另一个应该捕获带有1个参数的构造函数的函数。
module Main (
main
) where
data MyContainter a b = FirstVersion a b
| SecondVersion a
deriving(Show,Eq)
showContainer (FirstVersion a b) = show b
showContainer (SecondVersion a) = show a
--startF = showContainer (FirstVersion 1 2) -- it works
startF = showContainer (SecondVersion 1) -- it doesn't work
main = putStr startF
编译器告诉:
Ambiguous type variable `a0' in the constraint:
(Show a0) arising from a use of `showMaybe'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: showMaybe (SecondVersion 1)
In an equation for `startF': startF = showMaybe (SecondVersion 1)
为什么会这样说?我直接创建了(SecondVersion 1)并且不理解编译器为什么不调用showContainer(SecondVersion a)。
答案 0 :(得分:9)
问题是showContainer
的类型为:
showContainer :: (Show a, Show b) => MyContainer a b -> String
但是当您通过SecondVersion 1
时,它不知道b
是什么,因为SecondVersion 1
适用于任何类型的b
!当您传递FirstVersion
时,它可以正常工作,因为FirstVersion
同时包含a
和b
,因此对于它们应该是什么,从不存在任何歧义。< / p>
因此,由于编译器无法知道您想要的b
,并且无法知道b
的选择不会影响showContainer
(毕竟,它传递FirstVersion
时, 会影响行为,因为它对show
类型的值使用b
,它会放弃。
这就是错误消息所说的:类型变量a0
1 是不明确的,所以请添加一个类型签名来告诉我它是什么。在这种情况下,它无关紧要,因此您可以将其设置为()
:
startF = showContainer (SecondVersion 1 :: MyContainer Integer ())
您可能不会经常遇到这样的错误,因为您使用值的上下文通常会强制使用特定的b
。
1 不幸的是,GHC不是挑选类型变量的最佳选择;如果你给我showContainer
显式的显式类型签名,那么它也会在错误消息中使用b
。