Determine if a given tree is a binary search tree with lambda calculus - coq

can anyone help me to find out how to make a function that return true if a tree is a BST.
Definition binTree (A : Set) : Set := forall T : Set, T -> (T -> A -> T -> T) -> T.
Definition pET (A : Set) : binTree A := fun (T : Set) (x : T) (c : T -> A -> T -> T) => x.
Definition pNT (A : Set) (g : binTree A) (a : A) (d : binTree A) : binTree A :=
fun (T : Set) (x : T) (c : T -> A -> T -> T) => c (g T x c) a (d T x c).
I have tried this one , but that does not work.
function (isInf a b ) return true if a <= b
function (and a b) return ( a && b)
Definition is_BST ( t : binTree nat ) : bool :=
t bool true ( fun left racine right => (and (isInf left racine) ( isInf racine right))).

Related

Check cnat. and got Type return

All
I am trying to understand the Church numerals, mentioned in the SF-LF book, chp4.
Definition cnat := forall X : Type, (X -> X) -> X -> X.
Definition one : cnat :=
fun (X : Type) (f : X -> X) (x : X) => f x.
Check cnat.
Check one.
And I get
cnat
: Type
one
: cnat
It seems cnat is some kind of type, and function at the same time. How can it be both type and function? Anyone can help explain a little more about this?
The "forall (X : Type)," syntax is a way to form a type, from a type parameterized by X. forall (X : Type), (X -> X) -> X -> X is a type of functions, which given a type X produce a value of type (X -> X) -> X -> X (which is itself a function).
The "fun (X : Type) =>" syntax is a way to form a function, from a term parameterized by X. fun (X : Type) (f : X -> X) (x : X) => f x is a function, which given a type X produce the function fun (f : X -> X) (x : X) => f x (which is itself a function).
What fun and forall have in common is that they involve binders, like (X : Type) (also like (f : X -> X), (x : X)). fun is a construct that involves binders to form functions, but not all constructs that involve binders form functions: forall is a construct that involves binders to form types.

Are all homomorphisms proper?

Is a homomorphism between two groups proper? Here are my definitions for groups and homomorphisms:
Definition associative {ty : Type} (f : ty -> ty -> ty) (eq : ty -> ty -> Prop) :=
forall a b c, eq (f (f a b) c) (f a (f b c)).
Definition identity {ty : Type} (f : ty -> ty -> ty) (eq : ty -> ty -> Prop) (e : ty) :=
forall a, eq (f a e) a /\ eq (f e a) a.
Definition op_inverse {ty : Type} (f : ty -> ty -> ty) (eq : ty -> ty -> Prop) (e a a' : ty) :=
eq (f a a') e /\ eq (f a' a) e.
Definition op_invertible {ty : Type} (f : ty -> ty -> ty) (eq : ty -> ty -> Prop) (e : ty) :=
forall a, exists a', op_inverse f eq e a a'.
Record Group : Type := Group'
{ ty :> Type
; op : ty -> ty -> ty
; eqr : ty -> ty -> Prop
; e : ty
; eq_rel :> Equivalence eqr
; prop_op :> Proper (eqr ==> eqr ==> eqr) op
; assoc_op : associative op eqr
; id_op : identity op eqr e
; inv_op : op_invertible op eqr e
}.
Notation "A <.> B" := ((op _) A B) (at level 50).
Notation "A =.= B" := ((eqr _) A B) (at level 50).
Definition homomorphism {G H : Group} (f : G -> H) :=
forall x y, f (x <.> y) =.= (f x <.> f y).
I want to prove:
Lemma homo_is_proper : forall {G H : Group} (f : ty G -> ty H),
homomorphism f -> Proper (eqr G ==> eqr H) f.
Is this necessarily true?
It's not true.
Let H be a non-trivial group (e.g., Z/2Z), define G as the quotient of H under the total relation eqr := fun _ _ => True (G is thus isomorphic to the trivial group), and f : ty G -> ty H is the identity function. f satisfies homomorphism but it's not proper.
In general, to reflect common mathematical practice, when working with setoids, properness is a basic fact that must be proved from first principles, and that the rest of a theory rests upon. Arguably, homo_is_proper is not a natural question to ask, because all theorems and properties (such as homomorphism) should really be parameterized only by proper functions in the first place.

Why does coq's typechecker reject my map definition?

I try to experiment with list's definition.
For example let's see this definition:
Inductive list1 : Type -> Type := nil1 : forall (A : Type), list1 A
| cons1 : forall (A : Type), A -> list1 A -> list1 A.
You might think that the definition above is equivalent to this:
Inductive list0 (A : Type) : Type := nil0 : list0 A
| cons0 : A -> list0 A -> list0 A.
Why this map:
Fixpoint map0 {A : Type} {B : Type} (f : A -> B) (xs : list0 A) : list0 B :=
match xs with
nil0 _ => nil0 B
| cons0 _ v ys => cons0 B (f v) (map0 f ys)
end.
accepted, but this one is not:
Fail Fixpoint map1 {A : Type} {B : Type} (f : A -> B) (xs : list1 A) :=
match xs with
nil1 _ => nil1 B
| cons1 _ v ys => cons1 B (f v) (map1 f ys)
end.
?
This is indeed a confusing aspect of datatype definitions. The problem is that list1 is not equivalent to list0, because of how indices and parameters are treated in these definitions. In Coq jargon, an "index" means an argument declared to the right of the colon, as in list1. A "parameter", by contrast, is an argument declared to the left of the colon, as A in list0.
When you use an index, the return type of match expressions must be generic with respect to the index. This can be seen in the type of list1_rec, a combinator for writing recursive definitions on lists:
Check list1_rec.
list1_rec
: forall P : forall T : Type, list1 T -> Set,
(forall A : Type, P A (nil1 A)) ->
(forall (A : Type) (a : A) (l : list1 A), P A l -> P A (cons1 A a l)) ->
forall (T : Type) (l : list1 T), P T l
This type says that given a generic type P indexed by lists and an element l : list1 A, you can produce a result of type P A l by telling Coq what to return on nil1 and cons1. However, the type of the cons1 branch (the third argument of list1) says that the branch must work not only for the A that appears in the type of l, but also for all other types A'. Compare this to the type of list0_rec:
Check list0_rec.
list0_rec
: forall (A : Type) (P : list0 A -> Set),
P (nil0 A) ->
(forall (a : A) (l : list0 A), P l -> P (cons0 A a l)) ->
forall l : list0 A, P l
The branch of cons0 does not have the forall A bit, which means that the branch only has to work for the type A in l : list0 A.
This makes a difference when writing a function such as map. In map0, we are allowed to apply f : A -> B because we know that the argument of cons0 has type A. In map1, the argument of cons1 has a different generic type A', leading to this error message:
Fail Fixpoint map1 {A : Type} {B : Type} (f : A -> B) (xs : list1 A) :=
match xs with
nil1 A' => nil1 B
| cons1 A' v ys => cons1 B (f v) (map1 f ys)
end.
(* The term "v" has type "A'" while it is expected to have type "A". *)
To be complete, you can define function map over list1 :
Fixpoint map1 {A : Type} {B : Type} (f : A -> B) (xs : list1 A) :=
match xs with
| nil1 A' => fun _ => nil1 B
| cons1 A' v ys => fun f => cons1 B (f v) (map1 f ys)
end f.
This is an example of the so-called convoy pattern. Usually, one needs to add a return clause to the match construct so that it typechecks, but here Coq is smart enough to infer it.
However, I certainly discourage using this definition of lists as it will be cumbersome to use in similar cases.

Coq doesn't recognize equality of dependent list

I made a question before, but i think that question was bad formalized so...
I am facing some problems with this specific definition to prove their properties:
I have a definition of a list :
Inductive list (A : Type) (f : A -> A -> A) : A -> Type :=
|Acons : forall {x : A} (y' : A) (cons' : list f x), list f (f x y')
|Anil : forall (x: A) (y : A), list f (f x y).
And that's definitions :
Definition t_list (T : Type) := (T -> T -> T) -> T -> T.
Definition nil {A : Type} (f : A -> A -> A) (d : A) := d.
Definition cons {A : Type} (v' : A) (c_cons : t_list _) (f : A -> A -> A) (v'' : A) :=
f (c_cons f v'') v'.
Fixpoint list_correspodence (A : Type) (v' : A) (z : A -> A -> A) (xs : list func v'):=
let fix curry_list {y : A} {z' : A -> A -> A} (l : list z' y) :=
match l with
|Acons x y => cons x (curry_list y)
|Anil _ _ y => cons y nil
end in (#curry_list _ _ xs) z (let fix minimal_case {y' : A} {functor : A -> A -> A} (a : list functor y') {struct a} :=
match a with
|Acons x y => minimal_case y
|Anil _ x _ => x
end in minimal_case xs).
Theorem z_next_list_coorresp : forall {A} (z : A -> A -> A) (x y' : A) (x' : list z x), z (list_correspodence x') y' = list_correspodence (Acons y' x').
intros.
generalize (Acons y' x').
intros.
unfold list_correspodence.
(*reflexivity should works ?*)
Qed.
z_next_list_coorres is actually a lemma i need to prove a goal in another theory (v'_list x = (list_correspodence x)).
I have been trying with some limited scopes to prove list_correspodence and works well, seems that definitions are equal, but for coq not.
Here list_correspondence is a spurious Fixpoint (i.e., fix) (it makes no recursive calls), and this gets in the way of reduction.
You can force reduction of a fix by destructing its decreasing argument:
destruct x'.
- reflexivity.
- reflexivity.
Or you can avoid using Fixpoint in the first place. Use Definition instead.
You may run into a strange bug here with implicit arguments, which is avoided by adding a type signature (as below), or by not marking implicit the arguments of the local function curry_list:
Definition list_correspodence (A : Type) (v' : A) (func : A -> A -> A) (xs : list func v')
: A :=
(* ^ add this *)

When does the termination checker reduce a record accessor

I am stumbling about behavior of Coq’s termination checker that I cannot explain to myself. Consider:
Require Import Coq.Lists.List.
Record C a := { P : a -> bool }.
Arguments P {_}.
Definition list_P {a} (a_C : C a) : list a -> bool := existsb (P a_C).
Definition list_C {a} (a_C : C a) : C (list a) := {| P := list_P a_C |}.
(* Note that *)
Eval cbn in fun a C => (P (list_C C)).
(* evaluates to: fun a C => list_P C *)
Inductive tree a := Node : a -> list (tree a) -> tree a.
(* Works, using a local record *)
Fixpoint tree_P1 {a} (a_C : C a) (t : tree a) : bool :=
let tree_C := Build_C _ (tree_P1 a_C) in
let list_C' := Build_C _ (list_P tree_C) in
match t with Node _ x ts => orb (P a_C x) (P list_C' ts) end.
(* Works too, using list_P directly *)
Fixpoint tree_P2 {a} (a_C : C a) (t : tree a) : bool :=
let tree_C := Build_C _ (tree_P2 a_C) in
match t with Node _ x ts => orb (P a_C x) (list_P tree_C ts) end.
(* Does not work, using a globally defined record. Why not? *)
Fixpoint tree_P3 {a} (a_C : C a) (t : tree a) : bool :=
let tree_C := Build_C _ (tree_P3 a_C) in
match t with Node _ x ts => orb (P a_C x) (P (list_C tree_C) 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?
After some reading of the termination checker in Coq, I think I found the solution:
The termination checker will always unfold local definitions, and beta-reduce. That is why tree_P1 works.
The termination checker will also, if necessary, unfold definitions that are called (like list_C', P, existsb), that is why tree_P2 works.
Ther termination checker will, however, not unfold definitions that apppear in a match … with clause, such as list_C. Here is a minimal example for that:
(* works *)
Fixpoint foo1 (n : nat) : nat :=
let t := Some True in
match Some True with | Some True => 0
| None => foo1 n end.
(* works *)
Fixpoint foo2 (n : nat) : nat :=
let t := Some True in
match t with | Some True => 0
| None => foo2 n end.
(* does not work *)
Definition t := Some True.
Fixpoint foo3 (n : nat) : nat :=
match t with | Some True => 0
| None => foo3 n end.
A work-around for the original code is to make sure that all definitions are called (and not pattern-matched against), to ensure that the termination checker will unfold them. We can do that by switching to a continuation passing style:
Require Import Coq.Lists.List.
Record C_dict a := { P' : a -> bool }.
Definition C a : Type := forall r, (C_dict a -> r) -> r.
Definition P {a} (a_C : C a) : a -> bool :=
a_C _ (P' _).
Definition list_P {a} (a_C : C a) : list a -> bool := existsb (P a_C).
Definition list_C {a} (a_C : C a) : C (list a) :=
fun _ k => k {| P' := list_P a_C |}.
Inductive tree a := Node : a -> list (tree a) -> tree a.
(* Works now! *)
Fixpoint tree_P1 {a} (a_C : C a) (t : tree a) : bool :=
let tree_C := fun _ k => k (Build_C_dict _ (tree_P1 a_C)) in
match t with Node _ x ts => orb (P a_C x) (P (list_C tree_C) ts) end.
This even works with type classes, as type class resolution is indepenent of these issues:
Require Import Coq.Lists.List.
Record C_dict a := { P' : a -> bool }.
Definition C a : Type := forall r, (C_dict a -> r) -> r.
Existing Class C.
Definition P {a} {a_C : C a} : a -> bool := a_C _ (P' _).
Definition list_P {a} `{C a} : list a -> bool := existsb P.
Instance list_C {a} (a_C : C a) : C (list a) :=
fun _ k => k {| P' := list_P |}.
Inductive tree a := Node : a -> list (tree a) -> tree a.
(* Works now! *)
Fixpoint tree_P1 {a} (a_C : C a) (t : tree a) : bool :=
let tree_C : C (tree a) := fun _ k => k (Build_C_dict _ (tree_P1 a_C)) in
match t with Node _ x ts => orb (P x) (P ts) end.
For question 1. I believe that in tree_P1, the definition of the class instance is inside the fix construction and reduced at the time of termination checking.
The following definition is rejected, as you rightly point out.
Fixpoint tree_P1' {a} `{C a} (t : tree a) : bool :=
let tree_C := Build_C _ tree_P1' in
match t with Node _ x ts => orb (P x) (#P _ (* mark *) _ ts) end.
In this definition, the class instance needed after the comment (* mark *) is filled up by the definition you have on line 7. But this definition lives outside of the fix construct and won't be reduced by the termination checker in the same manner. As a result, an occurrence of tree_P1' that is not applied to any tree argument will remain in the code, and the termination checker won't be able to determine that this occurrence is only used on arguments that are smaller than the initial argument.
This is a wild guess, because we can't see the body of the function that is being rejected.