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

会成功,因为 xy 出去的类型与 xy 进来的类型相同(和 FirstPairSecondPair 与 GADT 所说的相符)。

如果你需要 return 一个 SecondPair String 无论如何,那么 myFunction 的类型签名是错误的,需要像

 myFunction :: Generator a -> SecondPair String

(在 Fail 的情况下不能正确执行——如果这是你真正想要走的路线,我还有更多要说的,但它比我想写的要复杂一些凭空猜测)

或者 GADT 需要说明结果将是 SecondPair String

 data Generator a where
     Success :: FirstPair a -> Generator (SecondPair String)
     ...

我认为这些情况不太可能发生,我只是认为它们可能有助于您理解问题。