Haskell 类型函数不能是内射的

Haskell 类型函数不能是内射的,haskell,Haskell,我试图证明一些关于奇偶自然数的公理。我在证明中使用了三种定义的数据类型 data Nat = Z | S Nat data Even (a :: Nat) :: * where ZeroEven :: Even Z NextEven :: Even n -> Even (S (S n)) data Odd (a :: Nat) :: * where OneOdd :: Odd (S Z) NextOdd :: Odd n -> Odd (S (S n)) 我还为

我试图证明一些关于奇偶自然数的公理。我在证明中使用了三种定义的数据类型

data Nat = Z | S Nat

data Even (a :: Nat) :: * where
  ZeroEven :: Even Z
  NextEven :: Even n -> Even (S (S n))

data Odd (a :: Nat) :: * where
  OneOdd :: Odd (S Z)
  NextOdd :: Odd n -> Odd (S (S n))
我还为加法和乘法定义了以下类型族

type family   Add (n :: Nat) (m :: Nat) :: Nat
type instance Add Z m = m
type instance Add (S n) m = S (Add n m)

type family   Mult (n :: Nat) (m :: Nat) :: Nat
type instance Mult Z m = Z
type instance Mult (S n) m = Add (Mult n m) n
我定义了函数来证明两个偶数的和是偶数,两个偶数的乘积是偶数

evenPlusEven :: Even n -> Even m -> Even (Add n m)
evenPlusEven ZeroEven m = m
evenPlusEven (NextEven n) m = NextEven (evenPlusEven n m)

evenTimesEven :: Even n -> Even m -> Even (Mult n m)
evenTimesEven ZeroEven m = ZeroEven
evenTimesEven (NextEven n) m = evenPlusEven (EvenTimesEven n m) n
我使用的是
GADTs
datatypes
TypeFamilies
,以及
不可判定实例
语言扩展和GHC 7.10.3版。运行
evenPlusEven
会得到我期望的结果,但是当我包含
eventimesven
时,我会得到一个编译错误。错误是:

Could not deduce (Add (Add (Mult n1 m) n1) ('S n1)
                  ~ Add (Mult n1 m) n1)
from the context (n ~ 'S ('S n1))
  bound by a pattern with constructor
             NextEven :: forall (n :: Nat). Even n -> Even ('S ('S n)),
           in an equation for `evenTimesEven'
  at OddsAndEvens.hs:71:16-25
NB: `Add' is a type function, and may not be injective
Expected type: Even (Mult n m)
  Actual type: Even (Add (Mult n1 m) n1)
Relevant bindings include
  m :: Even m
    (bound at OddsAndEvens.hs:71:28)
  n :: Even n1
    (bound at OddsAndEvens.hs:71:25)
  evenTimesEven :: Even n -> Even m -> Even (Mult n m)
    (bound at OddsAndEvens.hs:70:1)
In the expression: evenPlusEven (evenTimesEven n m) n
In an equation for `evenTimesEven':
    evenTimesEven (NextEven n) m = evenPlusEven (evenTimesEven n m) n
Mult
compile的类型族实例很好,如果我用错误抛出替换
evenTimesEven
的最后一行,我可以编译代码,并且函数运行良好,输入
ZeroEven
,这使我认为
Mult
的实例是正确的,我的
evenTimesEven
是问题所在,但我不确定原因


偶数(Mult n m)
偶数(Add(Mult n1 m)n1)
不应该有相同的类型吗

下面,我将滥用常用的数学符号

from the context (n ~ 'S ('S n1))
由此,我们得到
n=2+n1

Expected type: Even (Mult n m)
我们需要证明
n*m
偶数,即
(2+n1)*m
偶数

Actual type: Even (Add (Mult n1 m) n1)

我们已经证明了
(n1*m)+n1
是偶数。这是不一样的。附加的术语应该是
m
,而不是
n1
,并且应该添加两次。

不应该
evenPlusEven零偶m=n
be
evenPlusEven零偶m=m
?为
eventimesven
编写
*
evenPlusEven
编写
+
,为
nexteventimesven编写
,你已经写了
(2+n)*m=n*m+n
;它应该是
(2+n)*m=n*m+m+m
或类似的格式。我无法编译
evenPlusEven(evenTimesEven n m)(evenPlusEven m)
。这就是你想要的解决方案吗@4castle关联性很重要。这将使
(n*m)+(m+m)
但是我想你需要
((n*m)+m)+m)
。我心中没有解决方案,但如果在这样的练习中出现一些交换性或关联性问题,我不会感到惊讶。我发现一个打字错误,
Add(Mult n m)n
应该是
Add(Mult n m)m
,然后我应用了您的修复,现在它开始工作了!