Agda 关于使用重写的函数的证明:a";“目标中的竖条”;问题

Agda 关于使用重写的函数的证明:a";“目标中的竖条”;问题,agda,Agda,我有一个函数,它使用rewrite来满足Agda类型检查器的要求。我认为我已经相当好地掌握了如何在有关此类函数的证明中处理由此产生的“垂直条”。然而,在我看似简单的案例中,我完全无法处理这些障碍 这是导入和我的函数,步骤。rewrites使Agda看到n分别等于n+0,suc(acc+n)分别等于acc+suc n module Repro where open import Relation.Binary.PropositionalEquality as P using (_≡_) ope

我有一个函数,它使用
rewrite
来满足Agda类型检查器的要求。我认为我已经相当好地掌握了如何在有关此类函数的证明中处理由此产生的“垂直条”。然而,在我看似简单的案例中,我完全无法处理这些障碍

这是导入和我的函数,
步骤
rewrite
s使Agda看到
n
分别等于
n+0
suc(acc+n)
分别等于
acc+suc n

module Repro where

open import Relation.Binary.PropositionalEquality as P using (_≡_)

open import Data.Nat
open import Data.Nat.DivMod
open import Data.Nat.DivMod.Core
open import Data.Nat.Properties

open import Agda.Builtin.Nat using () renaming (mod-helper to modₕ)

step : (acc d n : ℕ) → modₕ acc (acc + n) d n ≤ acc + n
step zero d n rewrite P.sym (+-identityʳ n) = a[modₕ]n<n n (suc d) 0
step (suc acc) d n rewrite P.sym (+-suc acc n) = a[modₕ]n<n acc (suc d) (suc n)
此时,Agda告诉我,我不确定构造器p.refl是否应该存在,因为我在尝试解决以下统一问题(推断索引)时遇到了困难≟ 预期指数):w≟ w+0[…]

我还被困在第二个案例中,即
suc acc
案例中,尽管方式不同:

step-ok (suc acc) d n with suc (acc + n)  | P.sym (+-suc acc n)
step-ok (suc acc) d n    | .(acc + suc n) | P.refl = ?
这里,Agda表示suc(acc+n)!=w型ℕ 检查生成的with函数的类型[…]是否格式正确时

在Sassa NF回复后更新

我听从了Sassa NF的建议,用
p.subst
而不是
rewrite
重新编写了我的函数。也就是说,我将我的右手侧从大约
n+0
更改为大约
n
,而不是相反地将目标从大约
n
更改为大约
n+0

step′ : (acc d n : ℕ) → modₕ acc (acc + n) d n ≤ acc + n
step′ zero d n = P.subst (λ # → modₕ 0 # d # ≤ #) (+-identityʳ n) (a[modₕ]n<n n (suc d) 0)
step′ (suc acc) d n = P.subst (λ # → modₕ (suc acc) # d n ≤ #) (+-suc acc n) (a[modₕ]n<n acc (suc d) (suc n))
所以,耶!我刚刚用完成了我的第一个Agda证明

原始问题的一些进展

我的猜测是,我的第一个问题是依赖模式匹配期间的统一问题:没有任何替代使
n
n+0
相同。更一般地说,在一件事是另一件事的严格子项的情况下,我想我们可能会遇到麻烦。因此,可能使用
with
n
n+0
匹配是在问问题


我的第二个问题似乎是Agda语言引用所称的带有抽象的类型错误的
。根据参考资料,这种情况“当你对出现在目标或参数类型的子项类型中的术语进行抽象时发生。”罪魁祸首似乎是目标的子项类型
a[modₕ]n使用
p.refl
表示对
_≡_

这种类型没有魔力。它只是一个具有单个构造函数的依赖类型。证明了一些
x≡ y
解析为
P。refl
不会告诉Agda任何有关
x
y
的新信息:它只会告诉Agda您成功生成了类型为
_≡_
。这就是它无法分辨
n
(n+0)
是同一件事的原因,或者
suc(acc+n)
(acc+suc n)
相同。因此,您看到的两个错误实际上是相同的

现在,重写是为了什么

不能定义
cx≡ cy
对于依赖类型
C
cx
cy
是不同的类型。相等仅定义为相同类型的元素,因此甚至无法表示
cx
类型的元素与
cy
类型的元素具有可比性

然而,有一个归纳公理,它允许产生类型为
cy
的元素,如果您有类型为
cx
的元素和类型为
x的元素≡ y
。注意类型
_≡_-也就是说,您可以定义自己的类型,并构造这样一个函数,Agda将满足:

induction : {A : Set} {C : (x y : A) -> (x ≡ y) -> Set} (x y : A) (p : x ≡ y) ((x : A) -> C x x refl) -> C x y p
induction x .x refl f = f x
或归纳公理的简化版本:

transport : {A : Set} {C : A -> Set} (x y : A) (x ≡ y) (C x) -> C y
transport x .x refl cx = cx
在实践中,这意味着你得到了某件事的证明——例如,
a x≡ 一个x,但随后将此证明沿着等式传送≡ y
以获得证明
x≡ y
。这通常需要显式指定类型,在本例中为
{C=y->A x≡ y}
,并提供
x
y
cx
。因此,这是一个非常繁琐的过程,尽管学习者可以从这些步骤中获益

rewrite
然后是一种语法机制,它重写重写重写之前已知的术语类型,这样在重写之后就不需要这种
传输了。因为它是语法的,所以它会解释类型
_≡_以一种特殊的方式(因此,如果您定义自己的类型,您需要告诉Agda您正在使用另一种类型作为等式)。重写类型不是“告诉”Agda认为某些类型是相等的。它只是字面上用
y
替换类型签名中出现的
x
,因此现在您只需要用
y
refl
构造东西

说到这里,你可以明白为什么它适用于
step
。这里
rewrite p.sym…
n+0
替换了所有出现的
n
,包括函数的返回类型,所以现在它是
modₕ acc(acc+(n+0))d(n+0)≤ acc+(n+0)
。然后构造该类型的值就可以了


然后,
step ok
不起作用,因为您只需要模式匹配值。没有什么可以告诉您
n
(n+0)
都是一样的。但是
重写
会。或者你可以使用这样的函数
传输

这并不能回答你的问题,但可能有助于解决你原来的问题:
噢…聪明!几天前我发现了与证明无关的问题,但我完全忽略了它的用处。所以,非常感谢你的支持分享这一点。我现在肯定要重温无关性,因为我突然在我的证明中看到了这个模式,它会在哪里
step-ok (suc acc) d n with suc (acc + n)  | P.sym (+-suc acc n) | a[modₕ]n<n (suc acc) d n
...                      | .(acc + suc n) | P.refl              | rhs                      = {!!}
step-ok (suc acc) d n with suc (acc + n)  | P.sym (+-suc acc n) | a[modₕ]n<n (suc acc) d n | P.inspect (a[modₕ]n<n (suc acc) d) n
...                      | .(acc + suc n) | P.refl              | rhs                      | P.[ rhs-eq ]                         = {!!}
step-ok (suc acc) d n with suc (acc + n)  | P.sym (+-suc acc n) | a[modₕ]n<n (suc acc) d n | P.inspect (λ n → P.subst (λ # → modₕ (suc acc) # d n ≤ #) (P.sym (+-suc acc n)) (a[modₕ]n<n (suc acc) d n)) n
...                      | .(acc + suc n) | P.refl              | rhs                      | P.[ rhs-eq ]                                                                                                  rewrite +-suc acc n = rhs-eq 
induction : {A : Set} {C : (x y : A) -> (x ≡ y) -> Set} (x y : A) (p : x ≡ y) ((x : A) -> C x x refl) -> C x y p
induction x .x refl f = f x
transport : {A : Set} {C : A -> Set} (x y : A) (x ≡ y) (C x) -> C y
transport x .x refl cx = cx