我正在尝试为表示模块化空间中两个连续元素的类型创建决策函数。
(此代码派生from this excellent answer到我之前的一个问题。)
data PreceedsN : Nat -> Nat -> Nat -> Type where
PreceedsS : {auto prf : S a `LT` m} -> PreceedsN m a (S a)
PreceedsZ : {auto prf : S a = m} -> PreceedsN m a Z
doesPreceedN : (m : Nat) -> (a : Nat) -> (b : Nat) -> Dec (PreceedsN m a b)
doesPreceedN m a b with (S a `cmp` m)
doesPreceedN (S a + S d) a b | CmpLT d with (S a `decEq` b)
doesPreceedN (S a + S d) a b | CmpLT d | Yes prf = Yes ?bIsSa
doesPreceedN (S a + S d) a b | CmpLT d | No contra = No ?bNotSa
doesPreceedN (S m) m b | CmpEQ with (b `decEq` 0)
doesPreceedN (S m) m Z | CmpEQ | Yes prf = Yes PreceedsZ
doesPreceedN (S m) m b | CmpEQ | No contra = No ?saIsmAndbIsNotZ
doesPreceedN (S m) (m + (S d)) b | CmpGT d = No ?saCannotBeGTm
我已经尽了最大努力,但我还不知道我自己构建必要的证据,特别是矛盾的证明。你能指导我如何填写上面代码中的一个或多个holes吗?
此外,如果您使用任何方便的工具,例如absurd
,impossible
或tactics,您能解释一下它们的工作原理以及它们在证明中扮演的角色吗?
答案 0 :(得分:2)
虽然prf
- 构造函数中的PreceedsN
需要LTE
证据(LT a b
只是LTE (S a) b
的同义词),但您的第一个cmp
1}}只需拆分S a
。相反,您应该直接获得LTE
证明:
doesPreceedN m a b with (S (S a) `isLTE` m)
如果您不需要重复使用所有变量,省略with
案例中的重复会让事情变得更漂亮。因此,要使用LTE
重复您的版本,我们有:
| (Yes lte) = case (decEq b (S a)) of
Yes Refl => PreceedsS
No notlte => No ?contra_notlte
| (No notlte) with (decEq (S a) m)
| Yes eq = case b of
Z => Yes PreceedsZ
(S b) => No ?contra_notZ
| No noteq = No ?contra_noteq
在所有这些情况下,你需要一个来证明一些a -> Void
,所以你可以假设,你有a
。您可以创建一个引理(您的编辑器可能具有绑定)或使用带有案例拆分的lambda。对于像这里这样的短函数,我赞成后者。对于?contra_notZ
:
No (\contra => case contra of prec => ?contra_notZ)
如果你在prec
上分开,你就有了:
No (\contra => case contra of PreceedsS => ?contra_notZ)
检查洞,你会发现你有:
notlte : LTE (S (S b)) m -> Void
prf : LTE (S (S b)) m
prf
是PreceedsS
的隐含参数,因此要将其与范围匹配,您可以匹配它:
No (\contra => case contra of (PreceedsS {prf}) => notlte prf)
?contra_noteq
可以解决问题。
?contra_notlte
的lambda:
No notlte => No (\contra => case contra of
PreceedsS => ?contra_notlte_1
PreceedsZ => ?contra_notlte_2)
检查类型给出:
:t ?contra_notlte_1
notlte : (S a = S a) -> Void
:t ?contra_notlte_2
lte : LTE (S (S a)) m
prf : S a = m
?contra_notlte_2
是最棘手的,因为您无法应用notlte
。但是你可以看到lte : LTE (S m) m
之后应该是假的,所以我们为它创建一个函数:
notLTE : Not (LTE (S n) n)
notLTE LTEZero impossible
notLTE (LTESucc lte) = notLTE lte
现在我们有:
PreceedsZ {prf} => notLTE ?contra_notlte_2
?contra_notlte_2 : LTE (S n) n
我尝试用(rewrite prf in lte)
替换这个洞,但这不起作用,因为这个策略没有找到合适的属性来重写。但我们可以明确指出:
PreceedsZ {prf} => notLTE (replace prf lte)
> Type mismatch between
LTE (S (S a)) m
and
P (S a)
因此,我们通过设置P
明确设置{P=(\x => LTE (S x) m)}
。
结果:
doesPreceedN : (m : Nat) -> (a : Nat) -> (b : Nat) -> Dec (PreceedsN m a b)
doesPreceedN m a b with (S (S a) `isLTE` m)
| (Yes lte) = case (decEq b (S a)) of
Yes Refl => Yes PreceedsS
No notlte => No (\contra => case contra of
PreceedsS => notlte Refl
PreceedsZ {prf} => notLTE (replace prf {P=(\x => LTE (S x) m)} lte))
| (No notlte) with (decEq (S a) m)
| Yes eq = case b of
Z => Yes PreceedsZ
(S b) => No (\contra => case contra of (PreceedsS {prf}) => notlte prf)
| No noteq = No (\contra => case contra of
PreceedsS {prf} => notlte prf
PreceedsZ {prf} => noteq prf)
replace : (x = y) -> P x -> P y
只重写一个类型的一部分。
例如,对于(n + m = m + n)
,我们可以将n + m
的{{1}}部分替换为Vect (n + m) a
。这是Vect (m + n) a
,因此P=\to_replace => Vect to_replace a
只是一个函数P
。
在Type -> Type
中,我们需要明确doesPreceedN
。大多数情况下,P
(策略)可以自动找到此rewrite … in …
并应用P
。另一方面,replace
只是一个简单的函数replace
:
:printdef replace