我试图证明一些简单的事情:
open import Data.List
open import Data.Nat
open import Data.Bool
open import Data.Bool.Properties
open import Relation.Binary.PropositionalEquality
open import Data.Unit
repeat : ∀ {a} {A : Set a} → ℕ → A → List A
repeat zero x = []
repeat (suc n) x = x ∷ repeat n x
filter-repeat : ∀ {a} {A : Set a} → (p : A → Bool) → (x : A) → T (p x) → ∀ n →
filter p (repeat n x) ≡ repeat n x
我认为通过filter-repeat
上的模式匹配证明p x
会很容易:
filter-repeat p x prf zero = refl
filter-repeat p x prf (suc n) with p x
filter-repeat p x () (suc n) | false
filter-repeat p x prf (suc n) | true = cong (_∷_ x) (filter-repeat p x prf n)
但是,这会抱怨prf : ⊤
不属于T (p x)
类型。所以我想,好吧,这似乎是一个熟悉的问题,让我们甩出inspect
:
filter-repeat p x prf zero = refl
filter-repeat p x prf (suc n) with p x | inspect p x
filter-repeat p x () (suc n) | false | _
filter-repeat p x tt (suc n) | true | [ eq ] rewrite eq = cong (_∷_ x) (filter-repeat p x {!!} n)
但是尽管rewrite
,洞的类型仍然是T (p x)
而不是T true
。这是为什么?如何将其类型缩减为T true
,以便填写tt
?
解决方法
我可以使用T-≡
:
open import Function.Equality using (_⟨$⟩_)
open import Function.Equivalence
filter-repeat : ∀ {a} {A : Set a} → (p : A → Bool) → (x : A) → T (p x) → ∀ n →
filter p (repeat n x) ≡ repeat n x
filter-repeat p x prf zero = refl
filter-repeat p x prf (suc n) with p x | inspect p x
filter-repeat p x () (suc n) | false | _
filter-repeat p x tt (suc n) | true | [ eq ] = cong (_∷_ x) (filter-repeat p x (Equivalence.from T-≡ ⟨$⟩ eq) n)
但我仍然想了解为什么基于inspect
的解决方案无效。
答案 0 :(得分:5)
正如AndrásKovács所说,归纳案例要求prf
为T (p x)
类型,而您已通过模式匹配将其更改为⊤
p x
。一个简单的解决方案就是在filter-repeat
上的模式匹配之前递归调用p x
:
open import Data.Empty
filter-repeat : ∀ {a} {A : Set a} → (p : A → Bool) → (x : A) → T (p x) → ∀ n →
filter p (repeat n x) ≡ repeat n x
filter-repeat p x prf 0 = refl
filter-repeat p x prf (suc n) with filter-repeat p x prf n | p x
... | r | true = cong (x ∷_) r
... | r | false = ⊥-elim prf
有时也很有用
data Protect {a} {A : Set a} : A → Set where
protect : ∀ x → Protect x
filter-repeat : ∀ {a} {A : Set a} → (p : A → Bool) → (x : A) → T (p x) → ∀ n →
filter p (repeat n x) ≡ repeat n x
filter-repeat p x q 0 = refl
filter-repeat p x q (suc n) with protect q | p x | inspect p x
... | _ | true | [ _ ] = cong (x ∷_) (filter-repeat p x q n)
... | _ | false | [ r ] = ⊥-elim (subst T r q)
protect q
保存q
的类型不会被重写,但这也意味着在false
情况下,q
的类型仍然是T (p x)
比⊥
,因此额外的inspect
。
同一想法的另一个变体是
module _ {a} {A : Set a} (p : A → Bool) (x : A) (prf : T (p x)) where
filter-repeat : ∀ n → filter p (repeat n x) ≡ repeat n x
filter-repeat 0 = refl
filter-repeat (suc n) with p x | inspect p x
... | true | [ r ] = cong (x ∷_) (filter-repeat n)
... | false | [ r ] = ⊥-elim (subst T r prf)
module _ ... (prf : T (p x)) where
也可以防止prf
的类型被重写。
答案 1 :(得分:3)
依赖模式匹配仅在其使用的确切点影响目标和上下文。匹配p x
会重写当前上下文,并将prf
中的⊤
类型缩减为true
。
但是,当您执行递归filter-repeat
调用时,您再次提供x
作为参数,而T (p x)
中的filter-repeat
取决于 x
,而不是外部环境中的旧的,即使它们在定义上是平等的。假设我们可以传递x
以外的其他内容,因此在filter-repeat
调用之前不能对它做出任何假设。
x
可以通过从归纳中分解来使其在上下文中保持不变:
open import Data.Empty
filter-repeat : ∀ {a} {A : Set a} → (p : A → Bool) → (x : A) → T (p x) → ∀ n →
filter p (repeat n x) ≡ repeat n x
filter-repeat p x prf = go where
go : ∀ n → filter p (repeat n x) ≡ repeat n x
go zero = refl
go (suc n) with p x | inspect p x
go (suc n) | true | [ eq ] = cong (_∷_ x) (go n)
go (suc n) | false | [ eq ] = ⊥-elim (subst T eq prf)