如何在coq中将列表分成两半?

时间:2017-09-21 16:09:39

标签: coq

在我真正尝试使用它之前,它看起来绝对是一项简单的任务。我的方法是使用双指针以避免提前询问列表的长度,但困难来自于我确信一个列表比另一个列表“没有空闲”的暗示。具体来说,在伪coq中:

Definition twin_ptr (heads, tail, rem : list nat) :=
  match tail, rem with
  | _, [] => (rev heads, tail)
  | _, [_] => (rev heads, tail)
  | t :: tl, _ :: _ :: rm => twin_ptr (t :: heads) tl rm
  end.

Definition split (l : list nat) := twin_ptr [] l l

但是肯定不会编译因为匹配案例不完整。但是,构建中缺失的案例不存在。

你实施它的方式是什么?

3 个答案:

答案 0 :(得分:2)

您不需要维护第二个列表大于第三个列表的不变量。这是一个可能的解决方案:

<input #checkbox1 type="checkbox" [checked]="true" (change)="onChange(1, checkbox1)"/>{{name1}}
<br>
<input #checkbox2 type="checkbox" (change)="onChange(2, checkbox2)"/>{{name2}}

答案 1 :(得分:2)

我不害怕依赖类型,您可以添加rem短于tail的证明作为twin_ptr的参数。使用Program来帮助管理这些依赖类型,可以提供以下内容。

Require Import List. Import ListNotations.
Require Import Program.
Require Import Arith.
Require Import Omega.

Program Fixpoint twin_ptr
  (heads tail rem : list nat)
  (H:List.length rem <= List.length tail) :=
  match tail, rem with
  | a1, [] => (rev heads, tail)
  | a2, [a3] => (rev heads, tail)
  | t :: tl, _ :: _ :: rm => twin_ptr (t :: heads) tl rm _
  | [], _::_::_ => !
  end.
Next Obligation.
  simpl in H. omega.
Qed.
Next Obligation.
  simpl in H. omega.
Qed.

Definition split (l : list nat) := twin_ptr [] l l (le_n _).

感叹号表示分支无法访问。

然后,您可以证明twin_ptr的引理,并从中推断出split的属性。例如,

Lemma twin_ptr_correct : forall head tail rem H h t,
  twin_ptr head tail rem H = (h, t) ->
  h ++ t = rev head ++ tail.
Proof.
Admitted.

Lemma split_correct : forall l h t,
  split l = (h, t) ->
  h ++ t = l.
Proof.
  intros. apply twin_ptr_correct in H. assumption.
Qed.

就个人而言,我不喜欢在函数中使用依赖类型,因为生成的对象更难以操作。相反,我更喜欢定义总函数,并在引理中给出正确的假设。

答案 2 :(得分:0)

我建议采用更精确的类型吗?主要思想是定义一个函数,将Vector.t索引的形状为nat的{​​{1}}分成m + n大小为Vector.t,其中一个大小为{{} 1}}。

m

完成此操作后,您已将问题缩小为定义n的{​​{1}}和Require Import Vector. Definition split_vector : forall a m n, Vector.t a (m + n) -> (Vector.t a m * Vector.t a n). Proof. intros a m n; induction m; intro v. - firstorder; constructor. - destruct (IHm (tl v)) as [xs ys]. firstorder; constructor; [exact (hd v)|assumption]. Defined. ,并证明它们总和为floor

ceil

确实,您可以将n / 2转换为n并使用Fixpoint div2_floor_ceil (n : nat) : (nat * nat) := match n with | O => (O , O) | S O => (O , S O) | S (S n') => let (p , q) := div2_floor_ceil n' in (S p, S q) end. Definition div2_floor (n : nat) := fst (div2_floor_ceil n). Definition div2_ceil (n : nat) := snd (div2_floor_ceil n). Lemma plus_div2_floor_ceil : forall n, div2_floor n + div2_ceil n = n. Proof. refine (fix ih n := match n with | O => _ | S O => _ | S (S n') => _ end); try reflexivity. unfold div2_floor, div2_ceil in *; simpl. destruct (div2_floor_ceil n') as [p q] eqn: eq. simpl. replace p with (div2_floor n') by (unfold div2_floor ; rewrite eq ; auto). replace q with (div2_ceil n') by (unfold div2_ceil ; rewrite eq ; auto). rewrite <- plus_n_Sm; do 2 f_equal. apply ih. Qed. 获取每个部分。

length xs