Haskell无法统一类型实例方程

Haskell无法统一类型实例方程,haskell,ghc,Haskell,Ghc,我试图用(偶数/奇数)奇偶校验类型标记规范Nat数据类型,看看我们是否能得到任何自由定理。代码如下: {-# LANGUAGE GADTs #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DataKinds #-} -- Use DataKind promotion with type function for even-odd module EvenOdd where data Parity = Even | Odd -- Parit

我试图用(偶数/奇数)奇偶校验类型标记规范Nat数据类型,看看我们是否能得到任何自由定理。代码如下:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}

-- Use DataKind promotion with type function for even-odd

module EvenOdd where

  data Parity = Even | Odd
  -- Parity is promoted to kind level Parity.
  -- Even & Odd to type level 'Even & 'Odd of kind Parity

  -- We define type-function opp to establish the relation that
  -- type 'Even is opposite of 'Odd, and vice-versa
  type family Opp (n :: Parity) :: Parity
  type instance Opp 'Even = 'Odd
  type instance Opp 'Odd = 'Even

 -- We tag natural number with the type of its parity
  data Nat :: Parity -> * where
     Zero :: Nat 'Even
     Succ :: Nat p -> Nat (Opp p)

  -- Now we (should) get free theorems.
  -- 1. Plus of two even numbers is even
  evenPlus :: Nat 'Even -> Nat 'Even -> Nat 'Even
  evenPlus Zero n2 = n2  -- Line 31
  evenPlus (Succ (Succ n1)) n2 = Succ (Succ (evenPlus n1 n2))
但是,GHC抛出类型错误:

Could not deduce (p1 ~ 'Even)
from the context ('Even ~ Opp p)
  bound by a pattern with constructor
             Succ :: forall (p :: Parity). Nat p -> Nat (Opp p),
           in an equation for `evenPlus'
  at even-odd.hs:31:13-26
or from (p ~ Opp p1)
  bound by a pattern with constructor
             Succ :: forall (p :: Parity). Nat p -> Nat (Opp p),
           in an equation for `evenPlus'
  at even-odd.hs:31:19-25
  `p1' is a rigid type variable bound by
       a pattern with constructor
         Succ :: forall (p :: Parity). Nat p -> Nat (Opp p),
       in an equation for `evenPlus'
       at even-odd.hs:31:19
Expected type: Nat 'Even
  Actual type: Nat p
In the first argument of `evenPlus', namely `n1'
In the first argument of `Succ', namely `(evenPlus n1 n2)'
据我所知,上述错误的要点是,当上下文有以下等式时,GHC无法推断(p1~'偶数)((Opp(Opp p1))~'偶数)


为什么会发生这种情况?我的方法有什么问题吗?

我不认为GADT模式匹配优化可以这样工作。您将
Opp
作为构造函数的结果类型。所以如果你写了这样的东西

f :: Nat 'Even -> ...
f (Succ n) = ...
然后类型检查器知道
Nat(Opp t)~Nat'偶数
,因此
Opp t~偶数
。但要解决这个问题,类型检查器必须反转函数
Opp
,这要求很多

我建议您将
Nat
的定义改为:

data Nat :: Parity -> * where
  Zero :: Nat 'Even
  Succ :: Nat (Opp p) -> Nat p
这应该行得通

编辑 实际上,让我稍微扩展一下

上述建议并非没有(次要)价格。你失去了一点类型推断。例如,
succzero
的类型现在是
succzero::Opp~'偶数=>natp
而不是
Nat'Odd
。通过显式类型注释,它解析为ok

您可以通过向
Succ
添加一个约束来改进这一点,该约束要求
Opp
是自反转的。
奇偶校验
仅有的两个元素是
偶数
奇数
,对于这两个元素,约束是成立的,因此它不会导致任何问题:

data Nat :: Parity -> * where
  Zero :: Nat 'Even
  Succ :: (Opp (Opp p) ~ p) => Nat (Opp p) -> Nat p

现在
succzero
被推断为
Nat'Odd
类型,模式匹配仍然有效。

这有效,谢谢。我发现这两种方法在生成的类型约束方面有所不同。@GowthamKaki我在我的答案中添加了更多的细节。