Agda,证明类型和with子句

4
在AgdaIntro中,视图部分解释:

..使用with时不会记住with-term和模式之间的连接。

这意味着当你定义时,

data   False : Set where
record True  : Set where

isTrue : Bool -> Set
isTrue true  = True
isTrue false = False

infixr 30 _:all:_
data All {A : Set}(P : A -> Set) : List A -> Set where
  all[]   : All P []
  _:all:_ : forall {x xs} -> P x -> All P xs -> All P (x :: xs) 

satisfies : {A : Set} -> (A -> Bool) -> A -> Set
satisfies p x = isTrue (p x)

data Find {A : Set}(p : A -> Bool) : List A -> Set where
  found : (xs : List A)(y : A) -> satisfies p y -> (ys : List A) -> 
           Find p (xs ++ y :: ys)
  not-found : forall {xs} -> All (satisfies (not � p)) xs -> 
              Find p xs

你想证明

find1 :{A:Set}(p:A->Bool)(xs:ListA)->Find p xs 
find1 p [] = not-found all []
find1 p(x::xs) with p x
...| true  = found [] x {!!} xs
...| false = {!!}

尽管我们已经匹配并发现p x为真,但孔洞({!!})的类型是isTrue(p x)。

编译器不知道我们已经在p x上进行了模式匹配,并要求我们提供一个证明,证明p x为真!

这促使引入一个新类型,即

..一个类型A的元素类型与它们相等的证明,证明它们等于A中的某个给定x。

data Inspect {A : Set}(x : A) : Set where
  it : (y : A) -> x == y -> Inspect x

inspect : {A : Set}(x : A) -> Inspect x
inspect x = it x refl

使用这种类型,find函数可以这样编写:
trueIsTrue : {x : Bool} -> x == true -> isTrue x
trueIsTrue refl = _

falseIsFalse : {x : Bool} -> x == false -> isFalse x
falseIsFalse refl = _

find : {A : Set}(p : A -> Bool)(xs : List A) -> Find p xs
find p [] = not-found all[]
find p (x :: xs) with inspect (p x)
... | it true prf = found [] x (trueIsTrue prf) xs
... | it false prf with find p xs
find p (x :: ._) | it false _   | found xs y py ys =
  found (x :: xs) y py ys
find p (x :: xs) | it false prf | not-found npxs =
  not-found (falseIsFalse prf :all: npxs)

现在,如果我想要证明以下属性:

NOW,如果我想证明以下属性:

predicate : ∀ {A : Set} {p : A -> Bool } {xs : List A } -> 
            All (satisfies' p) (filter p xs)

我将会遇到与find相同的问题,因此我需要在inspect上进行模式匹配以获取证明,但是我还需要编译器在过滤器中进展,例如p x == true

如果我进行一些并行模式匹配,编译器会将它们视为独立表达式。

predicate {A} {p} {xs = []} = all[]
predicate {A} {p} {xs = x :: xs} with p x
predicate {A} {p} {x :: xs} | px with  inspect (p x) 
predicate {A} {p} {x :: xs} | true | it true pf = {!!}
predicate {A} {p} {x :: xs} | true | it false pf = {!!} 
predicate {A} {p} {x :: xs} | false | it true pf = {!!}
predicate {A} {p} {x :: xs} | false | it false pf = {!!}

我应该如何告诉编译器这两个分支有某种联系?我需要添加证明吗?

1个回答

4

请不要在p x上进行模式匹配:

predicate {A} {p} {xs = []} = all[]
predicate {A} {p} {x :: xs} with inspect (p x) 
predicate {A} {p} {x :: xs} | it true  pf rewrite pf = {!!}
predicate {A} {p} {x :: xs} | it false pf rewrite pf = {!!}

注意,inspect 习语已过时,请使用增强版检查。您可以在标准库这里找到它。
您的代码变成了:
predicate : ∀ {A : Set} {p : A -> Bool } {xs : List A } -> 
            All (satisfies p) (filter p xs)  
predicate {A} {p} {xs = []} = all[]
predicate {A} {p} {xs = x :: xs} with p x | inspect p x
predicate {A} {p} {x :: xs} | true  | [ pf ] = {!!}
predicate {A} {p} {x :: xs} | false | [ pf ] = {!!}

使用pf插入第一个孔。

.Data.Unit.Core.reveal (.Data.Unit.Core.hide p x) == true

这个式子可以被简化为 p x == true。也就是说,如果你有:

test : ∀ {A : Set} {p : A -> Bool} {x} -> p x == true -> True
test _ = _ 

然后将test {p = p} pf放入第一个空位并输入C-c C-d,你会得到True


啊,为什么我自己没有想到呢 :) 谢谢你的指导,我想今天下午我得仔细看看它。 - nicolas
相当棒。我不确定我是否真正理解了在“肌酸检查”中发挥作用的机制的整体情况。这句话“很容易证明,揭示x会给你揭示x:”强调了返回值被限制为特定类型,我想这是至关重要的。 - nicolas
@nicolas,如果你在谈论我最后一次编辑的内容,我已经删除了它,因为我不确定它是否有意义。等我确认后,我会把它还原。对此我很抱歉。 - effectfully
我之前没有看到被删除的编辑,现在看起来很不错,但即使现在的答案也提供了非常有用的链接,介绍了不同的策略:重写 VS 增强检查。更有用的是,它没有出现在 AgdaIntro pdf 中。你是否广泛使用 Agda? - nicolas
@nicolas,这可能是因为rewrite关键字只出现在Agda 2.2.6中。 “您是否广泛使用Agda?” ——不太,我只是在家里学习东西。 - effectfully

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接