我有以下自定义数据类型:
data FirstPair' a b = FirstPair a b deriving (Show, Ord, Eq)
type FirstPair a = FirstPair' a a
data SecondPair' a b = SecondPair a b deriving (Show, Ord, Eq)
type SecondPair a = SecondPair' a a
我正在尝试为我的函数创建一个GADT结构:
data Generator a where
Success :: FirstPair a -> Generator (SecondPair a)
Fail :: FirstPair a -> Generator Bool
myFunction :: Generator a -> a
myFunction (Success fp) = SecondPair "21" "24"
myFunction (Fail fp) = False
'Generator'类型的作用是让我强制'myFunction'返回'SecondPair'的实例,如果'Success'被传递给它,并且'False'如果'Fail'传递给它。< / p>
但是,我收到了这个错误:
"Could not deduce: a1 ~ [Char] from the context: a ~ SecondPair' a1 a1 bound by a pattern with constructor: Success :: forall a. FirstPair a -> Generator (SecondPair a)"
我在这里做错了什么?
答案 0 :(得分:4)
myFunction :: Generator a -> a
myFunction (Success fp) = SecondPair "21" "24"
myFunction (Fail fp) = False
问题出在这里。
是类型签名的简写myFunction :: forall a. Generator a -> a
也就是说,无论我选择哪种类型a
,如果我给myFunction
Generator a
,它会给我一个a
。因此,如果我给它Generator Int
,它应该给我一个Int
。
所以我可以构建
successval :: Generator (SecondPair Int)
successval = Success (FirstPair 42 42 :: FirstPair Int)
然后将其传递给myFunction
,并根据我应该获得的类型签名
myFunction successVal :: SecondPair Int
但是,myFunction
的定义方式,无论我传递的是什么类型,它总会返回SecondPair String
,这就是它所抱怨的问题。
如果你想要这种多态性,你需要以某种方式使用你给出的参数。 E.g。
myFunction (Success (FirstPair x y)) = SecondPair x y
可以解决这个问题,因为x
和y
的出现与进入的x
和y
的类型相同(FirstPair
和SecondPair
符合GADT所说的方式。
如果您无论如何都需要返回SecondPair String
,那么myFunction
的类型签名是错误的,需要像
myFunction :: Generator a -> SecondPair String
(在Fail
的情况下,它没有正确行动 - 我还有更多的话要说这是你真正想去的路线,但它比我更多参与想写一个黑暗的猜测)
或GADT需要说结果为SecondPair String
。
data Generator a where
Success :: FirstPair a -> Generator (SecondPair String)
...
我不认为这些是非常可能的情况,我只是认为它们可能有助于您理解问题。