coq-club AT inria.fr
Subject: The Coq mailing list
List archive
- From: Tej Chajed <tchajed AT mit.edu>
- To: coq-club <coq-club AT inria.fr>
- Subject: Re: [Coq-Club] When does the termination checker reduce a record accessor?
- Date: Fri, 3 Nov 2017 09:40:23 -0400
- Authentication-results: mail2-smtp-roc.national.inria.fr; spf=None smtp.pra=tchajed AT mit.edu; spf=Pass smtp.mailfrom=tchajed AT mit.edu; spf=None smtp.helo=postmaster AT dmz-mailsec-scanner-4.mit.edu
- Ironport-phdr: 9a23:oTl2Nx2AJ46dxqgDsmDT+DRfVm0co7zxezQtwd8ZsesQKvad9pjvdHbS+e9qxAeQG96Eu7QZ06L/iOPJZy8p2d65qncMcZhBBVcuqP49uEgeOvODElDxN/XwbiY3T4xoXV5h+GynYwAOQJ6tLw6annrn5jkLXx77KAA9cu/yA8vZi9m9/+G04ZzaJQtS0mmTe7R3eSm7r036tsAUjIcqfro6yhLLr3dgfuVKg25kOATAzF7H+s6s8cs7oGxrsPU7+psYXA==
I saw this on Stack Exchange and started looking into it. Your first question really surprised me - it appears you have dead code that helps the termination checker. What’s going on in that the let-bound list_C (I’ll call it list_C’ to avoid confusion with the definition it shadows) is used for typeclass instantiation rather than the global instance. Here’s a demonstration (note that I personally started with Set Typeclasses Debug
, but you can see the impact of typeclass resolution by looking at the terms before the termination checker runs):
Require Import Coq.Lists.List.
Class C a := { P : a -> bool }.
Definition list_P {a} `{C a} : list a -> bool := existsb P.
Instance list_C {a} `{C a} : C (list a) := { P := list_P }.
Opaque list_C.
(* Note that *)
Eval cbn in fun t C => (@P (list t) (@list_C t C)).
(* evaluates to: fun t C => list_P *)
Inductive tree a := Node : a -> list (tree a) -> tree a.
Set Printing All.
Fixpoint tree_P1' {a} `{C a} (t : tree a) {struct t} : bool.
Proof.
set (tree_C := Build_C _ (tree_P1' _ _)).
refine (match t with Node _ x ts => orb (P x) (P ts) end).
Show Proof.
Fail Guarded.
Abort.
(* Works *)
Fixpoint tree_P1'' {a} `{C a} (t : tree a) {struct t} : bool.
Proof.
set (tree_C := Build_C _ (tree_P1'' _ _)).
set (list_C' := Build_C _ list_P).
refine (match t with Node _ x ts => orb (P x) (P ts) end).
Show Proof.
(* note that list_C' is the argument to P this time *)
Defined.
So in tree_P2 it’s not evaluation but instead typeclass resolution not actually using the global list_C.
On Fri, Nov 3, 2017 at 9:27 AM, Joachim Breitner <mail AT joachim-breitner.de> wrote:
Hi,
I am stumbling about behavior of Coq’s termination checker that I
cannot explain to myself. Consider:
Require Import Coq.Lists.List.
Class C a := { P : a -> bool }.
Definition list_P {a} `{C a} : list a -> bool := existsb P.
Instance list_C {a} `{C a} : C (list a) := { P := list_P }.
(* Note that *)
Eval cbn in fun a C => (@P (list a) (@list_C a C)).
(* evaluates to: fun a C => list_P *)
Inductive tree a := Node : a -> list (tree a) -> tree a.
(* Works *)
Fixpoint tree_P1 {a} `{C a} (t : tree a) : bool :=
let tree_C := Build_C _ tree_P1 in
let list_C := Build_C _ list_P in (* Question 1: Why is this line needed *)
match t with Node _ x ts => orb (P x) (P ts) end.
Instance tree_C {a} `{C a} : C (tree a) := { P := tree_P1 }.
(* Works too *)
Fixpoint tree_P2 {a} `{C a} (t : tree a) : bool :=
let tree_C := Build_C _ tree_P2 in
match t with Node _ x ts => orb (P x) (list_P ts) end.
(* Does not work. Why not? *)
Fixpoint tree_P3 {a} `{C a} (t : tree a) : bool :=
let tree_C := Build_C _ tree_P3 in
match t with Node _ x ts => orb (P x) (@P _ (@list_C _ tree_C) ts) end.
(* And hence, this (identical?) code does not work *)
Fixpoint tree_P4 {a} `{C a} (t : tree a) : bool :=
let tree_C := Build_C _ tree_P4 in
match t with Node _ x ts => orb (P x) (P ts) end.
The first and second example show that, when trying to understand
whether a fixpoint is terminating, Coq is able to resolve record
accessors, basically evaluating what we wrote in tree_P1 to what we
wrote in tree_P2.
But this seems to only work if the record is built locally (let tree_C
:=…), not if it is defined using Definition.
But Fixpoint can look through other definitions just fine, e.g. through
list_P. So what is special about records, and can I make Coq accept
tree_P3 and tree_P4?
Thanks,
Joachim
--
Joachim Breitner
mail AT joachim-breitner.de
http://www.joachim-breitner.de/
- [Coq-Club] When does the termination checker reduce a record accessor?, Joachim Breitner, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, Tej Chajed, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, Joachim Breitner, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, William J. Bowman, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, Joachim Breitner, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, Joachim Breitner, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, William J. Bowman, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, Joachim Breitner, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, Joachim Breitner, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, Joachim Breitner, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, Maxime Dénès, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, William J. Bowman, 11/03/2017
- Re: [Coq-Club] When does the termination checker reduce a record accessor?, Tej Chajed, 11/03/2017
Archive powered by MHonArc 2.6.18.