从这个例子:
def getObject: ConnectionIO[Request] = ???
def saveObject(obj: Request): ConnectionIO[Request] = ???
def processObject(obj: Request): monix.eval.Task[Request] = ???
val transaction: ConnectionIO[Request] = for {
obj <- getObject //ConnectionIO[Request]
processed <- Async[ConnectionIO].liftIO(processObject(obj).toIO) //ConnectionIO[Request]
updated <- saveObject(processed) //ConnectionIO[Request]
} yield updated
val result: Task[Request] = transaction.transact(xa)
只需在第二个假设上做Example foo : forall (X : Type) (x y z : X) (l j : list X),
x :: y :: l = z :: j ->
y :: l = x :: j ->
x = y.
即可解决:
inversion
然而,在第一个假设中做Proof.
intros X x y z l j eq1 eq2. inversion eq2. reflexivity. Qed.
,产生了明显矛盾的假设:
inversion
因为,在最后一个证据中,生成的假设是:
Proof.
intros X x y z l j eq1 eq2. inversion eq2. inversion eq1. reflexivity. Qed.
但是,如果我没有遗漏一些明显的东西,那么H0 : y = x
H1 : l = j
H2 : x = z
H3 : y :: l = j
和H1
都不可能同时成立。
有人可以解释一下发生了什么吗?仅仅是这个例子是“糟糕的设计”(这两个假设都是矛盾的)而Coq倒置策略只是吞下它们吗?它是基于两个假设一起考虑的爆炸原理吗?如果是这样,那么仅仅通过从虚假中得出任何东西来证明这个例子是否可能?怎么样?
答案 0 :(得分:3)
你的例子是假设相互矛盾的假设:它们暗示length l + 2
等于length l + 1
。
Require Import Coq.Lists.List.
Require Import Omega.
Example foo : forall (X : Type) (x y z : X) (l j : list X),
x :: y :: l = z :: j ->
y :: l = x :: j ->
x = y.
Proof.
intros X x y z l j eq1 eq2.
apply (f_equal (@length _)) in eq1.
apply (f_equal (@length _)) in eq2.
simpl in *.
omega.
Qed.
根据爆炸原理,Coq能够得出一个矛盾的背景并不奇怪。
除了这种小怪异之外,所产生的假设是矛盾的这一事实并没有错:即使最初的假设是一致的,这种情境也会出现。考虑以下(公认的做作)证据:
Goal forall b c : bool, b = c -> c = b.
Proof.
intros b c e.
destruct b, c.
- reflexivity.
- discriminate.
- discriminate.
- reflexivity.
Qed.
第二和第三个分支具有相互矛盾的假设(true = false
和false = true
),即使最初的假设b = c
是无害的。这个例子与原始例子略有不同,因为通过组合假设没有获得矛盾。相反,当我们调用destruct
时,我们保证Coq通过考虑通过案例分析获得的一些子目标来证明结论。如果某些子目标恰好相互矛盾,甚至更好:那里没有任何工作要做。