What's with the `of` and `&` in the Coq Inductive definition? - coq

I just saw someone defined an Inductive type in Coq in an unfamiliar syntax, like this:
Inductive nat_tree : Type :=
| NatLeaf
| NatNode of color & nat_tree & nat & nat_tree.
The syntax I am used to look like this:
Inductive ident : sort :=
ident1 : type1
| …
| identn : typen
Can anyone explain what's the new syntax?
BTW, this is from a ssrflect tutorial. And I wonder if it's a ssr addition.

Yes, you are right: this syntax is defined by Ssreflect. Both are defined as syntactic sugar for declaring an anonymous argument: of T and & T mean (_ : T); that is, an unnamed argument of type T. Thus, the definition of nat_tree is equivalent to the one below.
Inductive nat_tree :=
| NatLeaf
| NatNode (_ : color) (_ : nat_tree) (_ : nat) (_ : nat_tree).
You could also have given names to each argument:
Inductive nat_tree :=
| NatLeaf
| NatNode (c : color) (t1 : nat_tree) (n : nat) (t2 : nat_tree).
As gallais pointed out, this makes the syntax of data-type declarations in Coq more similar to OCaml's. Note that the declaration above does not give the return type of each constructor. In standard Coq, specifying the return type is optional when all the arguments are given using this syntax, and when the type being defined is uniform. This means that we are allowed to define the list type as
Inductive list (T : Type) :=
| nil
| cons (t : T) (l : list T).
but are required to define the type of length-indexed lists as follows (because of the nat index):
Inductive vector (T : Type) : nat -> Type :=
| vnil : vector T O
| vcons (n : nat) (t : T) (v : vector T n) : vector T (S n).

Related

Overcoming the need of having a constructor in the definition of an other constructor

Most probably I'm trying to achieve something flawed, but I'm running into a need to have a constructor in the definition of another constructor.
Silly example:
Inductive silly_type : Type :=
| constr1 : nat -> silly_type
| constr2 : forall (x : silly_type), (exists n : nat, (x = constr1 n)) -> silly_type.
There are two ways how to create elements of silly_type, either with natural number and constr1 or using constr2 and element of silly_type that was created with constr1.
The above definition of silly_type is not valid in coq, but I do not know how to overcome this in my less silly example.
Less silly example:
I'm trying to have an inductive type expr representing typed expressions.
Let's first start with an inductive type representing types:
Inductive type : Type :=
| base_type : nat -> type
| arrow_type : type -> type -> type
| iso_arrow_type : type -> type -> type.
There are some base types indexed with integers, arrow_type representing function between types and iso_arrow_type representing invertible functions between types.
Notation:
Notation "A --> B" := (arrow_type A B) (at level 30, right associativity).
Notation "A <-> B" := (iso_arrow_type A B).
Type for expressions:
Inductive expr : type -> Type :=
| var : forall (X : type) (n : nat), expr X
| eval : forall {X Y : type} (f : expr (X --> Y)) (x : expr X), expr Y
| inv : forall {X Y : type}, expr ((X <-> Y) --> (Y <-> X))
| to_fun : forall {X Y : type}, expr ((X <-> Y) --> (X --> Y))
| to_iso : forall {X Y : type} (f : expr (X --> Y)), (is_invertible f) -> expr (Y --> X).
You can create an indexed variables of any type with var, evaluate a function with eval, invert an invertible function with inv, cast an invertible function to the actual function with to_fun such that you can evaluate it with eval.
The problem is with the last constructor to_iso. Sometimes, I will know that a function(element of X --> Y) is actually invertible and I want some mechanism to cast it to the type X <-> Y.
However, to define is_invertible I think that I need to use eval. This leads me to the problem that the constructor eval needs to be in the definition of the constructor to_iso.
To define is_invertible, we first need to define a notion of equality of expr:
Inductive ExprEq : forall (X : type), X -> X -> Prop :=
| expr_eq_refl : forall {X : type}, forall (x : X), ExprEq X x x
| eq_on_values : forall {X Y : type}, forall (f g : (X --> Y)), (forall (x : X), f[x] == g[x]) -> f == g
where
"x == y" := (ExprEq _ x y) and "f [ x ]" := (eval f x) and "x =/= y" := (not (ExprEq _ x y)).
Thus, we have standard reflexivity x == x and equality of functions f==g can be decided by equality on all elements f[x]==g[x].
Now, we are ready to define is_invertible:
Definition is_invertible {X Y : type} (f : X --> Y) : Prop := exists g : Y --> X, (forall x, g[f[x]] == x) /\ (forall y, f[g[y]] == y).
This definition of is_invertible is problematic, it is using eval(f[x] := (eval f x)). Furthermore, the problem is a bit more complicated. We need to define the type ExprEq that already uses eval to define its constructors.
Constrain: keep expr decidable
What I really want to preserve is that the equality(=) of expr is decidable, i.e. being able to prove
Lemma eq_expr_dec {X : type} (x y : type) : {x=y} + {x<>y}.
I really do not care about decidability of the defined equality ==, but decidability of = is important for me.
You can use dependent types to index your constructors. For example
Inductive silly_type : nat -> Type :=
| constr1 : nat -> silly_type 0
| constr2 : silly_type 0 -> silly_type 1.
So you can only use values produced by constr1 in constr2. This approach should work in general to distinguish values created with different constructors.

"Non strictly positive occurrence of ..."

I try to define the following type
Inductive t : Type -> Type :=
| I : t nat
| F : forall A, (t nat -> t A) -> t A.
and I get the following error:
Non strictly positive occurrence of "t" in "forall A : Type, (t nat -> t A) -> t A".
What does this error mean?
Is there a way to "fix" the definition to make it valid?
Where can I learn more about this?
Thanks!
You can look up common error messages in the Coq reference manual: https://coq.inria.fr/distrib/current/refman/language/gallina-specification-language.html?highlight=positive#coq:exn.non-strictly-positive-occurrence-of-ident-in-type
Essentially, if a constructor contains functions (such as t nat -> t A), they cannot mention the inductive type being defined as part of an argument (t nat).
vvvvvvvvvvvvvv argument
F : ... (t nat -> t A) -> t A
^ OK ("positive occurence")
^ Not OK ("negative occurence")
This section in Certified Programming with Dependent Types (CPDT) explains the problem with a simplified example: http://adam.chlipala.net/cpdt/html/Cpdt.InductiveTypes.html#lab30
If you could define the type
Inductive term : Set :=
| App : term -> term -> term
| Abs : (term -> term) -> term.
then you could define the function
Definition uhoh (t : term) : term :=
match t with
| Abs f => f t
| _ => t
end.
and uhoh (Abs uhoh) would diverge.

Prevent unintentional unfolding after application in Coq

My notation has been unintentionally unfolded after application.
I don't want to call the tactic 'change' on the last line in text of the tiny example every time I am using modus ponens.
How to forbid Coq to unfold my Notation "( a '==' b )"?
Require Export Coq.Vectors.Vector.
Import VectorNotations.
Inductive Terms : Type :=
FVC : nat -> Terms.
Definition Fo:=nat.
Context (axs0 : nat -> Type).
Context (Atom : Vector.t Terms 2 -> Fo).
Notation "( a '==' b )" := (Atom [a:Terms; b:Terms]).
Notation "( A --> B )" := (A + B).
Inductive GPR (axs : nat -> Type) (ctx:list nat) : nat -> Type :=
| MP (A B: Fo) : (GPR axs ctx A)->(GPR axs ctx (A --> B))
->(GPR axs ctx B).
Definition APR := GPR axs0.
Definition p2_23_a ctx (t:Terms) : APR ctx (t == t).
apply MP with (A:=(t == t)).
change (Atom [t; t]) with ((t==t)). (* <-- I don't want to write this line. *)
Change
Notation "( a '==' b )" := (Atom [a:Terms; b:Terms]).
to
Notation "( a '==' b )" := (Atom [a; b]).
Type annotations appear in the AST, and get easily simplified away, so the notation rarely matches.

Would it be inconsistent to relax Coq's strict positivity checker to not look at type indices of the inductive type being defined?

Writing
Inductive Foo : Type -> Type :=
| foo : Foo Bar
with
Bar := .
gives
Error: Non strictly positive occurrence of "Bar" in "Foo Bar".
I know the standard example of why strict positivity is necessary; if I have
Inductive Fix :=
| fFix : (Fix -> Fix) -> Fix.
with an eliminator
Fix_rect : forall (P : Fix -> Type) (v : forall f, (forall x, P (f x)) -> P (fFix f)) (f : Fix), P f
then I can prove absurdity with
Fix_rect (fun _ => False) (fun f H => H (fFix id)) (fFix id) : False
(Aside: Does anything go wrong if instead the eliminator is
Fix_rect : forall (P : Fix -> Type) (v : forall f, (forall x, P x -> P (f x)) -> P (fFix f)) (f : Fix), P f
?)
However, I don't see a way to make use of occurrences that appear only in indices. Is there a way to derive a similar contradiction if non-strictly-positive occurrences are permitted in type indices?
This doesn't seem to be a positivity issue, contrary to the error message. Rather, since you have mutual indexing, this is an inductive-inductive type (a weird "large" one at that), which Coq doesn't support.
You could try defining non-indexed types, and separate recursively defined "well-formedness" relations which encode correct indexing. E. g.
Inductive PreFoo : Type :=
| foo : PreFoo.
Inductive Bar : Type :=.
Fixpoint FooWf (f : PreFoo) (t : Type) : Prop :=
match f with
| foo => (t = Bar)
end.
Definition Foo (t : Type) := sig (fun f => FooWf f t).
This is analogous to how you might have indexed intrinsic syntaxes for type theories or extrinsic presyntaxes with separate typing relations.

How to write Definitions without arguments in Coq?

I have the following Inductive type defined in Coq.
Inductive natlist : Type :=
| nil : natlist
| cons : nat -> natlist -> natlist.
Notation "x :: l" := (cons x l) (at level 60, right associativity).
Notation "[ ]" := nil.
Notation "[ x , .. , y ]" := (cons x .. (cons y nil) ..).
The natlist is basically a list of natural numbers (similar to lists in Python). I am trying to find the union of two natlist using the definition below.
Definition union_of_lists : natlist -> natlist -> natlist
i.e
Eval simpl in (union_of_lists [1,2,3] [1,4,1])
should return [1,2,3,1,4,1]
I have the following doubts.
Since there are no arguments to this definition, how do I actually get the inputs and handle them?
What does the definition union_of_lists return exactly? Is it just a natlist?
Any help or hints are highly appreciated.
I found the answer myself :) What I did was, I wrote a separate Fixpoint function append and then assigned it to the definition of union_of_lists.
Fixpoint append(l1 l2 : natlist) : natlist :=
match l1 with
| nil => l2
| (h :: t) => h :: app t l2
end.`
and then
Definition union_of_lists : natlist -> natlist -> natlist := append.
Eval simpl in (append [1,2,3] [1,2,3]) (* returns [1,2,3,1,2,3] *)
The definition union_of_lists returns a function which takes natlist as an argument and returns another function of type natlist -> natlist (i.e function taking a natlist argument and returning a natlist).
This definition of union_of_lists resembles functions in Functional Programming which can either return a function or a value.