为什么 ghc 无法匹配此类别产品上的这些类型?

Sri*_*aic 6 haskell typeclass category-theory gadt

我对一个类别有一个非常典型的定义:

class Category (cat :: k -> k -> Type) where
  id :: cat a a
  (.) :: cat a b -> cat c a -> cat c b
Run Code Online (Sandbox Code Playgroud)

现在我想制作产品类别,所以我制作了这个 GADT

data ProductCategory
  (cat1 :: a -> a -> Type)
  (cat2 :: b -> b -> Type)
  (x :: (a, b))
  (y :: (a, b))
  where
MorphismProduct :: cat1 x x -> cat2 y y -> ProductCategory cat1 cat2 '(x, y) '(x, y)
Run Code Online (Sandbox Code Playgroud)

现在编译得很好,当我尝试将其作为Category. 这里的数学真的很简单,看起来这应该是一个简单的例子。所以这就是我想出的:

instance
  ( Category cat1
  , Category cat2
  )
    => Category (ProductCategory cat1 cat2)
  where
    id = MorphismProduct id id
    (MorphismProduct f1 f2) . (MorphismProduct g1 g2) = MorphismProduct (f1 . g1) (f2 . g2)
Run Code Online (Sandbox Code Playgroud)

但这出现了一个错误:

    • Couldn't match type ‘a2’ with ‘'(x0, y0)’
      ‘a2’ is a rigid type variable bound by
        the type signature for:
          id :: forall (a2 :: (a1, b1)). ProductCategory cat1 cat2 a2 a2
        at src/Galaxy/Brain/Prelude.hs:175:5-6
      Expected type: ProductCategory cat1 cat2 a2 a2
        Actual type: ProductCategory cat1 cat2 '(x0, y0) '(x0, y0)
    • In the expression: MorphismProduct id id
      In an equation for ‘id’: id = MorphismProduct id id
      In the instance declaration for
        ‘Category (ProductCategory cat1 cat2)’
    • Relevant bindings include
        id :: ProductCategory cat1 cat2 a2 a2
          (bound at src/Galaxy/Brain/Prelude.hs:175:5)
    |
175 |     id = MorphismProduct id id
    |          ^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

我在这个错误上花了很长时间,我只是不知道它试图与我交流什么。它声称它无法匹配a'(x0, y0)但我不知道为什么,它似乎真的应该能够匹配。

这里遇到的问题是什么?如何修复它会很好,但我真的很想知道如何阅读此消息。

Li-*_*Xia 3

id应该有类型forall a. MyCat a a,但在这种情况下你只能构造forall x y. MyCat '(x, y) '(x, y). 进一步推广需要假设所有对a :: (t1, t2)都是 形式a = '(x, y),这在 Haskell 中是无法证明的。

一种解决方法是不使用 GADT;特别是,不要细化构造函数中的类型参数。而不是这个:

data ProductCategory cat1 cat2 a b where
  Pair :: cat1 x x' -> cat2 y y' -> ProductCategory cat1 cat2 '(x, y) '(x', y')
Run Code Online (Sandbox Code Playgroud)

做这个:

data ProductCategory cat1 cat2 a b where
  Pair :: cat1 (Fst a) (Fst b) -> cat2 (Snd a) (Snd b) -> ProductCategory cat1 cat2 a b

type family Fst (a :: (k1, k2)) :: k1 where Fst '(x, y) = x
type family Snd (a :: (k1, k2)) :: k2 where Snd '(x, y) = y
Run Code Online (Sandbox Code Playgroud)

请注意, 的定义ProductCategory与此等效,没有 GADT 语法:

data ProductCategory cat1 cat2 a b
  = ProductCategory (cat1 (Fst a) (Fst b)) (cat2 (Snd a) (Snd b))
Run Code Online (Sandbox Code Playgroud)

  • 我有一个挥之不去的怀疑,这只是把石头踢得更远——好吧,现在你可以轻松创建“Pair”值,但它们不包含对象实际上是元组的知识。如果使用该类别的人想要掌握这些知识怎么办?那么他们是否不需要诉诸 HTNW 在评论中提到的“IsTuple”公理技巧? (3认同)