如何针对荒谬/无法构造的类型进行模式匹配?

时间:2018-07-18 15:40:01

标签: agda

根据我的理解,这两个定义a̶r̶e̶̶e̶q̶u̶i̶v̶a̶l̶e̶n̶t̶代表相同的行为:

data _<_ : ℕ → ℕ → Set where                       
    lt-zero : {n : ℕ} → zero < suc n
    lt-suc  : {m n : ℕ} → m < n → (suc m) < (suc n)

lt : ℕ → ℕ → Bool
lt  _       zero   = false
lt  zero   (suc n) = true
lt (suc m) (suc n) = m < n

除了_<_可以更容易地用于证明自己的事物,而且据我发现,lt更易于用于编程其他行为。例如,我可以看到如何使用min轻松定义lt函数:

min : ℕ → ℕ → ℕ
min x y where lt x y
... | true  = x
... | false = y

我是否可以使用min来定义_<_和其他类似功能?根据我的发现,如果x < y小于y,则无法进行模式匹配x。在这种情况下,有没有其他方法可以使用_<_

编辑:在_<_中添加不正确的案例会是一个明智的主意吗?

̶E̶D̶I̶T̶2̶:̶̶O̶r̶̶i̶s̶̶t̶h̶i̶s̶̶t̶h̶e̶̶'̶c̶o̶r̶r̶e̶c̶t̶'̶̶w̶a̶y̶̶t̶o̶̶d̶o̶̶i̶t̶?

编辑3:为了更改使用x <? ymin的证明,我更改了min的以下定义。

data _<?_ (n m : ℕ) : Set where
    isLT  : n < m → n <? m
    notLT : m ≤ n → n <? m

min : (x y : ℕ) → {p : x <? y} → ℕ
min x y (isLT _)  = x
min x y (notLT _) = y

这没有按预期工作。如果我确实使用C-c C-n评估min 1 2,则返回min 1 2。如果给出证明,我可以得到它返回最小值。但是,如果我评估min 2 1 (isLT _),它将返回2,而不是显示错误消息。我是否可以使用min来定义_<_,以便Agda可以评估min 1 2

1 个答案:

答案 0 :(得分:2)

有一种方法可以消除Agda中的不可能模式。使用您对_<_的定义 您可以尝试证明可传递性来说明这一点。

le-trans : ∀ {m n k} → m < n → n < k → m < k
le-trans {k = k} lt-zero b = {!!}
le-trans (lt-suc a) (lt-suc b) = lt-suc (le-trans a b)

Goal: 0 < k
b  : suc .n < k

我们对第一个参数进行模式匹配,分步情况是该假设的简单应用。在基本情况下,我们必须在k上进行模式匹配,因为您的数据类型的基本构造函数表示为zero < suc n,但我们对k仍然一无所知。在k上进行模式匹配后,我们看到了两种情况

le-trans : ∀ {m n k} → m < n → n < k → m < k
le-trans {k = zero} lt-zero b = {!!}
le-trans {k = suc k} lt-zero b = {!!}
le-trans (lt-suc a) (lt-suc b) = lt-suc (le-trans a b)

在第一个中,我们看到一些不可能的东西,即Goal: 0 < zero,并且我们有一个类型为b : suc .n < zero的元素,这是不可能发生的。然后,您可以在b上进行模式匹配,Agda将看到您无法构造这种东西,并将消除这种情况le-trans {k = zero} lt-zero ()。在其他情况下,您可以使用基本构造函数证明这一点。

le-trans : ∀ {m n k} → m < n → n < k → m < k
le-trans {k = zero} lt-zero ()
le-trans {k = suc k} lt-zero b = lt-zero
le-trans (lt-suc a) (lt-suc b) = lt-suc (le-trans a b)

因此,在数据类型中定义不正确的大小写是不合适的。您定义元素的构造方式。您对_<?_的最后一个定义很合理,实际上可以使用。

min上编辑

一旦您拥有_<?_的归纳关系,就可以按以下方式工作。定义一个为您提供m <? n的函数,然后为min函数进行抽象调用该函数。

data _≥_ : ℕ → ℕ → Set where
  get-z : ∀ {n} → n ≥ zero
  get-s : ∀ {m n} → m ≥ n → (suc m) ≥ (suc n)

data _<?_ (n m : ℕ) : Set where
  y-< : n < m → n <? m
  n-< : n ≥ m → n <? m

f<? : (m n : ℕ) → m <? n
f<? zero zero = n-< get-z
f<? zero (suc n) = y-< lt-zero
f<? (suc m) zero = n-< get-z
f<? (suc m) (suc n) with f<? m n
f<? (suc m) (suc n) | y-< x = y-< (lt-suc x)
f<? (suc m) (suc n) | n-< x = n-< (get-s x)

min : ℕ → ℕ → ℕ
min x y with f<? x y
min x y | y-< _ = x
min x y | n-< _ = y