简体   繁体   English

Coq将功能扩展为目标的一部分是什么意思?

[英]What does it mean when Coq expands a function as part of the goal?

I was trying to solve the following theorem and got stuck at the last simpl. 我试图解决以下定理,并陷入最后的simpl. :

Lemma nonzeros_app : forall l1 l2 : natlist,
  nonzeros (l1 ++ l2) = (nonzeros l1) ++ (nonzeros l2).
Proof.
  intros l1 l2. induction l1 as [| n' l' IHl'].
  -simpl. reflexivity.
  -simpl. 
Qed.

at that point Coq changes the goal from: 那时,Coq将目标从:

1 subgoal (ID 170)

  n' : nat
  l', l2 : natlist
  IHl' : nonzeros (l' ++ l2) = nonzeros l' ++ nonzeros l2
  ============================
  nonzeros ((n' :: l') ++ l2) = nonzeros (n' :: l') ++ nonzeros l2

to: 至:

1 subgoal (ID 185)

  n' : nat
  l', l2 : natlist
  IHl' : nonzeros (l' ++ l2) = nonzeros l' ++ nonzeros l2
  ============================
  match n' with
  | 0 => nonzeros (l' ++ l2)
  | S _ => n' :: nonzeros (l' ++ l2)
  end =
  match n' with
  | 0 => nonzeros l'
  | S _ => n' :: nonzeros l'
  end ++ nonzeros l2

which seems completely mysterious to me. 在我看来,这完全是个谜。 What does it mean when Coq just copy pastes the definition of a function into my goal? Coq只是复制将函数的定义粘贴到我的目标中是什么意思? What do I even do with this? 我什至要怎么办?


Context of Question: 问题背景:

Someone told me that the solution is: 有人告诉我解决方案是:

Lemma nonzeros_app : forall l1 l2 : natlist,
  nonzeros (l1 ++ l2) = (nonzeros l1) ++ (nonzeros l2).
Proof.
  intros l1 l2. induction l1.
  - simpl. reflexivity.
  - simpl. { induction n.
             - ...
             - ... }
Qed.

which made me want to understand why they use induction on n since it feels it would never occur to me to use induction there. 这让我想了解为什么他们在n上使用归纳法,因为我觉得在那里永远不会发生归纳法。 So I am asking, why? 所以我问,为什么? But I realized that before I could ask that why I didn't even understand the proof state before that since it just seemed to copy paste a function to a proof state (which makes no sense to me). 但是我意识到,在问起我为什么之前甚至不了解证明状态之前,我就意识到了,因为这似乎只是将粘贴复制到了证明状态(这对我来说没有意义)。 So before I asked why use induction there I have to ask what does the proof state before that, maybe that would yield light into why induction on n . 因此,在我问为什么使用归纳法之前,我必须问一下在此之前证明状态是什么,也许这将阐明为什么对n归纳法。

I am assuming that you have defined nonzeros in the following way (or similar): 我假设您已通过以下方式(或类似方式)定义了nonzeros

Require Import List.
Import ListNotations.


Definition natlist := list nat.

Fixpoint nonzeros (l : natlist) :=
  match l with
  | [] => []
  | 0 :: xs => nonzeros xs
  | x :: xs => x :: nonzeros xs
  end.

So that nonzeros is recursive with structural decreasing on l . 因此, nonzeros是递归的,结构递减为l Coq's simpl tactic employs a heuristic in which it unfolds definitions of fixpoints if they are applied to a term that has a constructor as the head symbol. Coq的simpl策略采用了一种启发式方法,在该方法中,如果将固定点的定义应用于以构造函数作为开头符号的术语,则会展开固定点的定义。 In your case, eg, nonzeros (n' :: l') , the constant nonzeros is followed by a term formed by a constructor, Cons (= :: ). 在您的情况下,例如nonzeros (n' :: l') ,常量nonzeros后跟由构造函数Cons (= :: nonzeros构成的项。 Coq performs a so-called "delta reduction", replacing the occurrence of nonzero with its definition. Coq执行所谓的“减少增量”,用其定义替换nonzero的出现。 Since that definition is a match , you get a match as your new term. 由于该定义是match ,因此您将获得一个match作为新术语。 Further substitutions do simplify it a bit, but cannot eliminate the two cases: one for zero head and one for nonzero head. 进一步的替换确实使它简化了一点,但是不能消除两种情况:一种表示零水头,一种表示非零水头。

Same happens to the occurrence nonzeros ((n' :: l') ++ l2) , which is first simplified to nonzeros (n' :: (l' ++ l2)) , so that again, the head of the argument is Cons . 出现的nonzeros ((n' :: l') ++ l2)发生同样的情况,首先将其简化为nonzeros (n' :: (l' ++ l2)) ,因此参数的开头为Cons

If you want to avoid exposing match expressions when simplifying, you can put the following directive after the definition of nonzeros : 如果要避免在简化时公开match表达式,可以将以下伪指令放在nonzeros的定义nonzeros

Arguments nonzeros l : simpl nomatch.

This specifically tells simpl to avoid expanding a term if this will end up exposing a match at the location of the change. 这特别是告诉simpl ,如果会最终在更改位置公开match项,则避免扩展术语。

As for the induction used by your friend here: it is applied to force a case split over n' , so that each case ( n' = 0 , n' = S _ ) can be handled separately. 至于您的朋友在这里使用的induction :它用于强制将案例拆分为n' ,以便可以分别处理每个案例( n' = 0n' = S _ )。 Indeed, induction is not needed here. 实际上,这里不需要归纳法。 A simple case split ( case n' ) will do the same. 一个简单的案例拆分( case n' )将执行相同的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM