伊德里斯的简易句法平等

时间:2015-05-19 00:07:15

标签: idris

是否有一种简单的方法可以为数据类型编写相等(DecEq)实例?例如,我希望以下内容在其DecEq声明中包含O(n)行,其中?p很简单:

data Foo = A | B | C | D

instance [syntactic] DecEq Foo where
   decEq A A = Yes Refl
   decEq B B = Yes Refl
   decEq C C = Yes Refl
   decEq D D = Yes Refl
   decEq _ _ = No ?p

1 个答案:

答案 0 :(得分:8)

大卫·克里斯蒂安森正在研究一些事情来实现这一点的自动化,他基本上已经完成了;它可以在his GitHub repository中找到。与此同时,在这种情况下,这是一种可以将你从O(n ^ 2)个案带到O(n)个案例的方法。首先是一些预赛。如果您有可判定的相等性,并且您从所选类型注入到该类型,那么您可以为该类型做出决策过程:

IsInjection : (a -> b) -> Type
IsInjection {a} f = (x,y : a) -> f x = f y -> x = y

decEqInj : DecEq d => (tToDec : t -> d) ->
                      (isInj : IsInjection tToDec) ->
                      (p, q : t) -> Dec (p = q)
decEqInj tToDec isInj p q with (decEq (tToDec p) (tToDec q))
  | (Yes prf) = Yes (isInj p q prf) 
  | (No contra) = No (\pq => contra (cong pq)) 

不幸的是,直接证明你的函数是一个注入会让你回到O(n ^ 2)个案例,但通常情况下任何具有撤销的函数都是单射的:

retrInj : (f : d -> t) -> (g : t -> d) ->
          ((x : t) -> f (g x) = x) ->
          IsInjection g
retrInj f g prf x y gxgy =
  let fgxfgy = cong {f} gxgy
      foo = sym $ prf x
      bar = prf y
  in trans foo (trans fgxfgy bar)

因此,如果您有一个函数,从您选择的类型到具有可判定的等式的函数和它的撤销,那么您的类型具有可判定的相等性:

decEqRet : DecEq d => (decToT : d -> t) ->
           (tToDec : t -> d) ->
           (isRet : (x : t) -> decToT (tToDec x) = x) ->
           (p, q : t) -> Dec (p = q)
decEqRet decToT tToDec isRet p q =
  decEqInj tToDec (retrInj decToT tToDec isRet) p q

最后,您可以根据自己选择的内容编写案例:

data Foo = A | B | C | D

natToFoo : Nat -> Foo
natToFoo Z = A
natToFoo (S Z) = B
natToFoo (S (S Z)) = C
natToFoo _ = D

fooToNat : Foo -> Nat 
fooToNat A = 0
fooToNat B = 1
fooToNat C = 2
fooToNat D = 3

fooNatFoo : (x : Foo) -> natToFoo (fooToNat x) = x
fooNatFoo A = Refl
fooNatFoo B = Refl
fooNatFoo C = Refl
fooNatFoo D = Refl

instance DecEq Foo where
  decEq x y = decEqRet natToFoo fooToNat fooNatFoo x y

请注意,虽然natToFoo函数的模式有些大,但实际上并没有那么多。应该可以通过嵌套来使图案变小,尽管这可能很难看。

概括:起初我认为这只适用于特殊情况,但我现在认为它可能比这更好一些。特别是,如果你有一个包含可判定等式的类型的代数数据类型,你应该能够将它转换为嵌套Either的嵌套Pair,这将使你到达那里。例如(使用Maybe缩短Either (Bool, Nat) ()):

data Fish = Cod Int | Trout Bool Nat | Flounder

watToFish : Either Int (Maybe (Bool, Nat)) -> Fish
watToFish (Left x) = Cod x
watToFish (Right Nothing) = Flounder
watToFish (Right (Just (a, b))) = Trout a b

fishToWat : Fish -> Either Int (Maybe (Bool, Nat))
fishToWat (Cod x) = Left x
fishToWat (Trout x k) = Right (Just (x, k))
fishToWat Flounder = Right Nothing

fishWatFish : (x : Fish) -> watToFish (fishToWat x) = x
fishWatFish (Cod x) = Refl
fishWatFish (Trout x k) = Refl
fishWatFish Flounder = Refl

instance DecEq Fish where
  decEq x y = decEqRet watToFish fishToWat fishWatFish x y