I'm writing a library in Coq that depends on user-supplied type parameters. One central part is a construction along the lines of
Require Import Ascii.
Require Import String.
Parameter UserType : Set. (* <<- placeholder for this example *)
Parameter UserToString : UserType -> string.
Inductive Tag : Set := TBool | TNat | TUser | TList : Tag -> Tag | TSum : Tag -> Tag -> Tag.
Fixpoint decodeT (t : Tag) : Set :=
match t with
| TBool => bool
| TNat => nat
| TUser => UserType (* <<- needed here *)
| TList t' => list (decodeT t')
| TSum l r => sum (decodeT l) (decodeT r)
end.
(* ...etc..., including: *)
Definition tostring (t : Tag) (v : decodeT t) : string := (* match t with ... end *) "dummy".
(* and other stuff *)
so I can't avoid those Parameters in some form. The whole library is split across multiple files, and because of the size it would be pretty uncomfortable to put everything in one file.
There's a top-level wrapper that exports all sub-modules. Ideally, I'd like to pass the parameters once when importing the library, and then this wrapper can do some magic to propagate them to all sub-modules, so that afterwards I don't have to worry about it anymore.
I've looked into various approaches, but nothing worked so far.
If I wrap the file contents in Sections, then the Parameters become extra arguments only on the definitions that use them, and then I have to manually splice them in everywhere when using the library's functions from outside.
If I don't wrap them in a Section, they are module parameters but I can't find a way to actually provide the value. (All forms of with Definition seem to require a module signature / Module Type? Duplicating all names & types to make an explicit signature would be prohibitively redundant, so maybe there is a way to make it work, but I couldn't find it. The documentation is also rather unhelpful...) Variations like using Context instead seem to have the same problem, as far as I tested things.
I'm happy to make a Module Type UserDefs (or typeclass, or whatever) that combines all the user definitions in a single value. I just don't know how to actually get it into the submodules.
So how do I do it? What needs to happen inside that sample file above, and what needs to happen on the outside, so that I can pass the definitions in once and then get a fully configured library to Import?
then I have to manually splice them in everywhere when using the library's functions from outside.
This is typically addressed by a mix of implicit parameters and type classes.
Declare a class for user-provided parameters.
Class UserParams : Type :=
{ UserType : Set
; UserToString : UserType -> string
}.
(* Make sure UserType and UserToString have UserParams as a maximally inserted implicit *)
Then in your library open sections parameterized by instances of that class:
Require Import Ascii.
Require Import String.
Section MyLib.
Context {userParams : UserParams}. (* Context generalizes Variable and allows you to set implicitness *)
Inductive Tag : Set := TBool | TNat | TUser | TList : Tag -> Tag | TSum : Tag -> Tag -> Tag.
Fixpoint decodeT (t : Tag) : Set :=
match t with
| TBool => bool
| TNat => nat
| TUser => UserType (* <<- needed here *)
| TList t' => list (decodeT t')
| TSum l r => sum (decodeT l) (decodeT r)
end.
(* ...etc..., including: *)
Definition tostring (t : Tag) (v : decodeT t) : string := (* match t with ... end *) "dummy".
(* and other stuff *)
End MyLib.
Then users instantiate the class
Require Import MyLib.
Instance myParams : UserParams :=
{| UserType := ...
; UserToString := ... |}.
And then your library functions will automatically be instantiated when you use them.
Related
What does the with keyword without the match do inside a inductive type in Coq?, example:
Inductive Block : Type :=
| EmptyBlk : Block
| Blk : Statement -> Block
with Statement : Type :=
| Assignment : string -> AExp -> Statement
| Seq : Statement -> Statement -> Statement
| IfElse : BExp -> Block -> Block -> Statement
| While : BExp -> Block -> Statement.
I tried checking the type of Statement and it seems its not of type block or something...So what is the point of defining it inside another inductive type rather than by itself. At least checking the type of Statement gives Set the same as for Block...
It is used to specify mutually recursive definitions. For example, consider the following two functions:
Fixpoint even (n : nat) : bool :=
match n with
| O => true
| S n => odd n
end
with odd (n : nat) : bool :=
match n with
| O => false
| S n => even n
end.
Here, you cannot define even first because it needs odd to be defined. You cannot define odd first either because it needs even. You need to be able to define both at the same time - and you do that by using the with keyword.
Your example is similar but defines inductive datatype rather than recursive function - Statement uses Block in its definition and Block uses Statement. Hence, with to define them both at the same time.
Note that this with is completely different keyword than with from the match expressions. In fact, they belong to two different languages: the former one is part of Vernacular whereas the latter is part of Gallina.
Consider the following code:
Require Import FMapAVL.
Require Import Coq.Structures.OrderedTypeEx.
Module NatMap := FMapAVL.Make(Nat_as_OT).
Inductive ttree (K : Type) (V : Type) :=
| tleaf : ttree K V
| tnode : ttree K V -> K -> V -> ttree K V -> nat -> ttree K V.
Inductive test :=
| test1 : test
| test2 : ttree nat test -> test
| test3 : list test -> test
| test4 : NatMap.t test -> test.
In Coq 8.6, I get Error: Non strictly positive occurrence of "test" in "NatMap.t test -> test". I get no error without test4.
Why does applying a NatMap.t (FMapAVL with nat keys) constructor to my test inductive type creates a non strictly positive occurence while applying list constructor or even ttree constructor (which is just like internal structure of FMapAVL) okay?
What are the common workarounds if I want something like test4 from my example, preferably ones not requiring me to make my own map implementation like that ttree?
The problem is that Coq can't handle some higher-order inductive types as nested inductives - I'm not convinced I fully understand the limitations, but I investigated a bit.
One important fact that helps explain the behavior is that Coq has special support for passing an inductive type to a type constructor. CPDT's Inductive Types chapter explains this in the section on Nested Inductive Types: Coq creates a version of list or ttree specialized to test and pretends you're defining tree and these specialized inductives with mutual induction. This generally works fine (such as for your list and even ttree definitions). It even works for modules, as long as they use "transparent ascription" (and FMapAVL.Make does so). However, it seems to break down when the type is an index instead of a parameter (that is, when the Type is to the right of the colon instead of the left):
Module Type Transformer.
Axiom T:Type -> Type.
End Transformer.
Module IdOpaque : Transformer.
Definition T (t:Type) := t.
End IdOpaque.
Inductive transformer : Type -> Type :=
| MkT : forall t, t -> transformer t .
(* make the argument a parameter *)
Inductive transformer' (t:Type) : Type :=
| MkT' : t -> transformer' t.
Module IdInd <: Transformer.
Definition T : Type -> Type := transformer.
End IdInd.
Module IdTransparent <: Transformer.
Definition T (t:Type) : Type := t.
End IdTransparent.
(* works with a simple definition, even inside a module, as long as its
transparent *)
Inductive test1 :=
| mkTest1 (_:IdTransparent.T test1).
(* not strictly positive (Coq can't see definition) *)
Fail Inductive test2 :=
| mkTest2 (_:IdOpaque.T test2).
(* this is pretty much what happens with FMapAVL.Make *)
Fail Inductive test3 :=
| mkTest3 (_:IdInd.T test3).
(* even this fails *)
Fail Inductive test4 :=
| mkTest4 (_:transformer test4).
(* this finally works *)
Inductive test5 :=
| mkTest5 (_:transformer' test5).
In Coq, what's the difference between ... ?
Require X.
Import X.
Require Import X.
I have basically memorized some common patterns. I usually see code using Require Import X. Then there's Import ListNotation. And I just noticed it's also possible to write just Require X. What's the difference? Some practical examples would be appreciated.
Require loads a library whereas Import brings its definitions into scope. Require Import does both. If you only have the library loaded, you'll need to refer to names fully qualified. Coq allows top-level modules corresponding to files to define modules; these have to be imported separately to bring all of their definitions into scope, and they can't be Required - that's what's going on with ListNotations:
(* List is not loaded by default *)
Fail Check List.map.
(* the full name is technically Coq.Lists.List *)
Require List.
(* note that lists are actually defined in Coq.Init.Datatypes which is
imported by default, so [list] is unqualified and the [x::xs] notation is
already defined *)
Print List.map.
(*
List.map =
fun (A B : Type) (f : A -> B) =>
fix map (l : list A) : list B :=
match l with
| nil => nil
| (a :: t)%list => (f a :: map t)%list
end
: forall A B : Type, (A -> B) -> list A -> list B
*)
(* bring everything in List into scope *)
Import List.
(* this includes the ListNotations submodule *)
Import ListNotations.
(* note that now list notations are available, and the list notation scope is
open (from importing List) *)
Print List.map.
(*
map =
fun (A B : Type) (f : A -> B) =>
fix map (l : list A) : list B :=
match l with
| [] => []
| a :: t => f a :: map t
end
: forall A B : Type, (A -> B) -> list A -> list B
*)
Note there are some quirks with how Coq handles modules, especially compared to other languages:
Coq does not require a full path to a module, only an unambiguous suffix. Indeed I rarely see full import paths, even to standard library modules.
Notations cannot be used except by importing the module, and unlike most objects there's no way to refer to a notation, fully qualified or otherwise.
Importing a module can have side effects, for example changing notation interpretation scopes or setting options if you use Global Set in the module being imported.
Importing is fairly limited (especially compared to Haskell) - there's no way to rename a module at import time, or selectively import some definitions.
I want to set Coq up, without redefining the : with a notation (and without a plugin, and without replacing the standard library or redefining the constants I'm using---no cheating like that), so that I have something like a partial coercion from option nat to nat, which is defined only on Some _. In particular, I want
Eval compute in Some 0 : nat.
to evaluate to 0, and I want
Check None : nat.
to raise an error.
The closest I've managed is the ability to do this with two :s:
Definition dummy {A} (x : option A) := A.
Definition inverted_option {A} (x : option A)
:= match x with Some _ => A | _ => True end.
Definition invert_Some {A} (x : option A) : inverted_option x
:= match x with Some v => v | None => I end.
Coercion invert_Some : option >-> inverted_option.
Notation nat' := (inverted_option (A:=nat) (Some _)).
Eval compute in (Some 0 : nat') : nat.
Check (None : nat') : nat.
(* The term "None" has type "option ?A" while it is expected to have type
"nat'". *)
However, this only works when nat' is a notation, and I can't define a coercion out of a notation. (And trying to define a coercion from inverted_option (Some _) to nat violated the uniform inheritance condition.) I thought I might be able to get around this issue by using canonical structures, but I haven't managed to figure out how to interleave canonical structure resolution with coercion insertion (see also Can canonical structure resolution be interleaved with coercion insertion?).
(I ran into this issue when attempting to answer Coq: Defining a subtype.)
This is a simple Coq syntax newbie question.:)
I am trying to define simple polynomial function on semi_rings:
Require Import Vector.
Import VectorNotations.
Require Import Ring_theory.
Section Polynomial_def.
Variable Asring : Type.
Variable (asr_0 asr_1 : Asring) (asr_add asr_mul: Asring->Asring->Asring).
Variable SRth : semi_ring_theory asr_0 asr_1 asr_add asr_mul eq.
Fixpoint evalPolynomial {n} (a: t Asring n) (x:Asring) : Asring :=
match a with
nil => asr_0
| cons a0 p a' => asr_add a0 (asr_mul x (evalPolynomial a' x))
end.
End Polynomial_def.
When I use it on Reals, for example, I have to do something like this:
Require Import Reals.Rdefinitions.
evalPolynomial R R0 Rplus Rmult a v
I suspect there should be a simpler syntax, where I can just pass single data structure (like comm_ring_1 in Isabelle) which will encapsulate all fields like R,R0,Rplus,Rmult for given type.
Yes, you can package all of your parameters in a structure and then pass that as an argument, something like
Structure semiring := Semiring {
Asring : Type;
asr_0 : Asring;
asr_1 : Asring;
asr_add : Asring -> Asring -> Asring
(* Other fields... *)
}.
Then, you can rephrase your development in terms of this structure:
Section Polynomial_def.
Variable sr := semiring.
Fixpoint evalPolynomial {n} (a: t (Asring sr) n) (x:Asring sr) : Asring sr :=
(* ... *)
Later, when trying to use that, you just have to build such a structure and pass it as a normal argument. You can also use Coq type classes or canonical structures to tell Coq how to pass such arguments automatically.