GADT 与自定义数据类型混淆?
GADT confusion with custom data types?
我有以下自定义数据类型:
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'到return一个'SecondPair'的实例,如果'Success'被传递给它,和 'False' 如果 'Fail' 传递给它。
但是,我遇到了这个错误:
"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)"
我在这里做错了什么?
myFunction :: Generator a -> a
myFunction (Success fp) = SecondPair "21" "24"
myFunction (Fail fp) = False
问题就在这里。类型签名是 shorthand for
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
,这就是它抱怨的问题。
如果你想要这种多态性,你需要以某种方式使用给定的参数。例如
myFunction (Success (FirstPair x y)) = SecondPair x y
会成功,因为 x
和 y
出去的类型与 x
和 y
进来的类型相同(和 FirstPair
和 SecondPair
与 GADT 所说的相符)。
如果你需要 return 一个 SecondPair String
无论如何,那么 myFunction
的类型签名是错误的,需要像
myFunction :: Generator a -> SecondPair String
(在 Fail
的情况下不能正确执行——如果这是你真正想要走的路线,我还有更多要说的,但它比我想写的要复杂一些凭空猜测)
或者 GADT 需要说明结果将是 SecondPair String
。
data Generator a where
Success :: FirstPair a -> Generator (SecondPair String)
...
我认为这些情况不太可能发生,我只是认为它们可能有助于您理解问题。
我有以下自定义数据类型:
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'到return一个'SecondPair'的实例,如果'Success'被传递给它,和 'False' 如果 'Fail' 传递给它。
但是,我遇到了这个错误:
"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)"
我在这里做错了什么?
myFunction :: Generator a -> a
myFunction (Success fp) = SecondPair "21" "24"
myFunction (Fail fp) = False
问题就在这里。类型签名是 shorthand for
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
,这就是它抱怨的问题。
如果你想要这种多态性,你需要以某种方式使用给定的参数。例如
myFunction (Success (FirstPair x y)) = SecondPair x y
会成功,因为 x
和 y
出去的类型与 x
和 y
进来的类型相同(和 FirstPair
和 SecondPair
与 GADT 所说的相符)。
如果你需要 return 一个 SecondPair String
无论如何,那么 myFunction
的类型签名是错误的,需要像
myFunction :: Generator a -> SecondPair String
(在 Fail
的情况下不能正确执行——如果这是你真正想要走的路线,我还有更多要说的,但它比我想写的要复杂一些凭空猜测)
或者 GADT 需要说明结果将是 SecondPair String
。
data Generator a where
Success :: FirstPair a -> Generator (SecondPair String)
...
我认为这些情况不太可能发生,我只是认为它们可能有助于您理解问题。