我可以使用值的正常形式来避免 Agda 中的不完整模式匹配吗?

Can I use the normal form of a value to avoid incomplete pattern matches in Agda?

在下面的 Agda 程序中,尽管 myList 只适合 cons 的情况,但我收到了关于 one 定义中缺失情况的警告。

open import Data.Nat

data List (A : Set) : Set where
  nil : List A
  cons : A → List A → List A

myList : List ℕ
myList = cons 1 (cons 2 (cons 3 nil))

one : ℕ
one with myList 
... | (cons x xs) = x
Incomplete pattern matching for .test.with-16. Missing
cases:
  one | nil

我知道这听起来有点令人费解,但有没有一种方法可以根据 myList 定义 one,而不会将 运行 变成 "incomplete pattern matching" 错误?

这个例子是我原来的问题的简化,它来自家庭作业,使用了稍微复杂的类型。在那种情况下,"myList" 是一个由小输入的聪明函数计算出的大值。如果我使用 Emacs 的 Agda 模式 (C-c C-n) 计算 "myList" 的正常形式,我可以从中获取 "one" 的值并将其粘贴到我的程序中。然而,这个值在打印出来时需要几十行,所以我在徘徊是否有一种方法可以根据 "myList" 直接定义 "one",而不会 运行 进入不完整的模式匹配错误。

如果您使用 with e,那么 e 会从目标和上下文中抽象出来(想想 lambda 抽象),并且您会被要求继续,就好像那里有一个变量而不是 e 本身。因此,以下模式匹配根本没有考虑 myList 的值(相当 counter-intutive,但 with 只是用于创建带有一个额外参数的辅助定义的语法糖)。

然而你可以写下:

open import Agda.Builtin.List
open import Agda.Builtin.Nat renaming (Nat to ℕ)
open import Agda.Builtin.Equality

myList : List ℕ
myList = 1 ∷ 2 ∷ 3 ∷ []

head : {n : ℕ} {ns : List ℕ} (xs : List ℕ) → n ∷ ns ≡ xs → ℕ
head (x ∷ xs) refl = x

one : ℕ
one = head myList refl

您还可以查看标准库中的 inspect 模式以获得更通用的解决此问题的方法。

您可以在类型级别反映一个值,然后对其进行模式匹配。看起来像这样:

open import Data.Nat

data List (A : Set) : Set where
  nil : List A
  cons : A → List A → List A

myList : List ℕ
myList = cons 1 (cons 2 (cons 3 nil))

data Sing {α} {A : Set α} : A -> Set where
  sing : ∀ x -> Sing x

one : ℕ
one with sing myList
... | sing (cons x (cons _ (cons _ nil))) = x