Agda - 以交互方式构建证明 - 如何使用 hole 语法?

Agda - Building proofs interactively - How to use the hole syntax?

抱歉这个奇怪的标题,我不知道这些概念实际上是如何命名的。

我正在学习 Agda 教程,其中有一节解释了如何以归纳方式构建证明:https://plfa.github.io/Induction/#building-proofs-interactively

很酷,您可以逐步扩展您的证明并让漏洞(此 { }0)更新其内容以告诉您发生了什么。但是,仅解释了在使用 rewrite 语法时如何执行此操作。

当我想 "manually" 在 begin 块内进行证明时,这是如何工作的,例如:

+-assoc : ∀ (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
+-assoc zero n p =
  begin
    (zero + n) + p
    ≡⟨⟩ n + p
    ≡⟨⟩ zero + (n + p)
  ∎
+-assoc (suc m) n p =
  begin
    (suc m + n) + p
    ≡⟨⟩ suc (m + n) + p
    ≡⟨⟩ suc ((m + n) + p)
    ≡⟨ cong suc (+-assoc m n p) ⟩
      suc (m + (n + p))
    ≡⟨⟩ suc m + (n + p)
  ∎

问题如下。先从命题说起,开始论证:

+-assoc : ∀ (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
+-assoc m n p = ?

计算结果为:

+-assoc : ∀ (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
+-assoc m n p = { }0

在这种情况下,我想通过归纳法进行证明,所以我使用 C-c C-c 使用变量 m:

拆分它们
+-assoc : ∀ (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
+-assoc zero n p = { }0
+-assoc (suc m) n p = { }1

基本情况很简单,在使用 C-c C-r 解析后用 refl 替换。然而,电感外壳(孔 1)需要做一些工作。如何把这个{ }1洞变成下面的结构来做证明:

begin
  -- my proof
  ∎

我的编辑器 (spacemacs) 说 { }1 是 read-only。我无法删除它,只能在大括号之间插入内容。我可以 force-delete 但这显然不是故意的。

你应该怎么做才能把洞扩大成 begin 方块?像这样

{ begin }1

不起作用并导致错误消息

谢谢!

编辑:

好的,以下似乎有效:

{ begin ? }1

这变成了这个:

+-assoc : ∀ (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
+-assoc zero n p = refl
+-assoc (suc m) n p = begin { }0

这是一个进步 :D。但是现在我不知道把证明的实际步骤放在哪里:

...
+-assoc (suc m) n p = begin (suc m + n) + p { }0
-- or
+-assoc (suc m) n p = begin { (suc m + n) + p }0

似乎都不起作用

{ }1 is read-only

此消息在两种情况下显示:

  • 您正在尝试使用退格键删除一个洞,但这是行不通的。不过,如果孔是空的,您可以使用 C-backspace
  • 您正在尝试在 insert/overwrite 模式下编辑一个空洞,这也行不通

一条经验法则是,您始终使用 C-c C-SPC 使用与目标类型相同的表达式来细化孔。在您的情况下,这意味着从 begin ? 开始,然后给出 (suc m + n) + p ≡⟨⟩ ? 等等。

有两种细化孔的方法:

  • C-c C-r:给定一个函数时为你创建新的洞。例如。使用此设置:

    test : Bool
    test = {!!}
    

    如果你在洞里输入 not

    test : Bool
    test = {!not!}
    

    再细化,你会得到

    test : Bool
    test = not {!!}
    

    即新洞是自动为参数创建的。

    通过这种方式或完善一个漏洞,Agda 还会按照它喜欢的方式重新格式化你的代码,我不喜欢这种方式,所以我通常不使用它。

  • C-c C-SPC:不会为参数创建新的漏洞,也不会重新格式化您的代码