【问题标题】:Call a theorem using let-in使用 let-in 调用定理
【发布时间】:2026-01-24 18:15:02
【问题描述】:

我有一个函数 f 返回一对。然后我证明了一些关于它的结果。 在我的引理中,我第一次尝试获取每个组件是使用let (x, y) := f z in。但是,尝试使用这些引理似乎很麻烦。 apply 不能直接工作,我必须使用 pose proof 或其变体在假设中添加引理并破坏 f z 才能使用它。有没有办法在引理中顺利使用 let-in ?还是因为使用起来很痛苦而气馁?

为了完成我的问题,这里是我写关于f 的引理的其他尝试。我尝试直接使用fst (f z)snd (f z),但我也发现它很麻烦。最后,我以forall x y, (x,y) = f z -> 开始了我的引理。

这是一个具体的例子。

Require Import List. Import ListNotations.

Fixpoint split {A} (l:list A) :=
  match l with
  | [] => ([], [])
  | [a] => ([a], [])
  | a::b::l => let (l1, l2) := split l in (a::l1, b::l2)
  end.

Lemma split_in : forall {A} (l:list A) x,
  let (l1, l2) := split l in 
  In x l1 \/ In x l2 <-> In x l.

Lemma split_in2 : forall {A} (l:list A) x,
  In x (fst (split l)) \/ In x (snd (split l)) <-> In x l.

Lemma split_in3 : forall {A} (l:list A) x l1 l2,
  (l1, l2) = split l ->
  In x l1 \/ In x l2 <-> In x l.

【问题讨论】:

    标签: coq


    【解决方案1】:

    您已经找到了我认为正确的解决方案。 let (l1, l2) := ... in ... 将阻止减少并破坏一切。使用split_in2 还是split_in3 取决于你的出发点是什么。

    但是请注意,打开Primitive Projections 并将prod 重新定义为原始记录将使split_insplit_in2 实际上是相同的定理,因为split l(fst (split l), snd (split l)) 是判断性的平等的。你可以这样做

    Set Primitive Projections.
    Record prod {A B} := pair { fst : A ; snd : B }.
    Arguments prod : clear implicits.
    Arguments pair {A B}.
    Add Printing Let prod.
    Notation "x * y" := (prod x y) : type_scope.
    Notation "( x , y , .. , z )" := (pair .. (pair x y) .. z) : core_scope.
    Hint Resolve pair : core.
    

    【讨论】:

    • 我相信我们还需要Arguments pair {A B}. 让它更像标准的prod 类型。
    • 不,我在prod 的定义中在{A B} 周围添加了花括号(它会自动为pairfstfstsnd 添加它们),然后将它们从prod.
    • 它对我不起作用(Coq 8.7.1):Check (0,0) : nat * nat,因为pair 有这些类型参数显式
    • @AntonTrunov 呵呵,我从来没有意识到花括号仅适用于类型前和投影,而不适用于构造函数。谢谢!
    • @eponier 关于默认开启,我刚刚做了github.com/coq/coq/issues/6609