Update single record field in Coq - record

I have a record type with a lot of fields:
Record r : Set :=
R {
field1 : nat;
field2 : nat;
field3 : nat;
...
field2137 : nat;
}
I would like to have a function that will update just one field in this record. In Haskell I would do it like this
update2019 record x = record {field2019 = x}
How can I perform such an action in Coq?

Unfortunately, Coq lacks support for record update. Luckily for us, there is coq-record-update library by #tchajed that greatly simplifies this. Here is an example:
From RecordUpdate Require Import RecordSet.
Import RecordSetNotations.
Record r : Set :=
R {
f1 : nat;
f2 : nat;
f3 : nat;
}.
Instance eta_r : Settable _ := settable! R <f1; f2; f3>.
Definition update3 record x : r := record <| f3 := x |>.
Please see the library's README.md file for more detail.

Related

Data type that represents the proof that two functions are equivalent

I was trying to make a data type that represents that fact that two functions are equivalent. What does the error mean?
Code:
record FEq (f1 : a -> b) (f2 : a -> b) where
constructor MkFEq
unFEq : (x : a) -> (f1 x = f2 x)
Error:
Type checking ./FEq.idr
FEq.idr:1:1-3:36:
|
1 | record FEq (f1 : a -> b) (f2 : a -> b) where
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ...
When checking type of Main.FEq.unFEq:
When checking argument x to type constructor =:
Type mismatch between
free_a b a f1 f2 rec
and
a
AFAIK you are not allowed to mention unbound parameters in a record.
So you have to add a and b as parameters like so:
record FEq a b (f1 : a -> b) (f2 : a -> b) where
constructor MkFEq
unFEq : (x : a) -> (f1 x = f2 x)

Elm record updating mismatch with type alias

I have the following type:
type alias SelList a =
{ list : List a
, selected : Maybe a
}
A Sel(ectable)List a is a list of a from which I can possibly choose an element.
In my application, all my objects have an id : Int field, so I've defined this type alias :
type alias HasId r = { r | id : Int}
Now I would like a function eventually selecting an element in the list, I've tried :
select : Int -> SelList (HasId r)-> Maybe (SelList (HasId r))
select id sl = find (\x-> x.id ==id) sl.list &> \ el ->
Just { sl | selected = el }
where (&>) = flip Maybe.andThen and find : (a -> Bool) -> List a -> Maybe a.
I've got the following message:
The type annotation for `select` says it always returns:
Maybe (SelList (HasId r))
But the returned value (shown above) is a:
Maybe { list : List (HasId r), selected : { r | id : Int } }
I'm confused because { r | id : Int } is the same than HasId, and then
{ list : List (HasId r), selected : HasId r }
is the same than SelList (HasId r). Why the compiler can not figure out that the types match?
The compiler's error is 90% of the way there, but I think mixing type aliases and records makes it harder to figure out what's wrong. (Future versions of Elm are going to improve this).
If it was a record and not a Maybe record, the compiler would tell you something like "I see a problem with the selected field`". Does that help?
Spoiler: The SelList type has a selected : Maybe a, but select returns selected : a

Is there a more convenient way to use nested records?

As I told before, I'm working in a library about algebra, matrices and category theory. I have decomposed the algebraic structures in a "tower" of record types, each one representing an algebraic structure. As example, to specify a monoid, we define first a semigroup and to define a commutative monoid we use monoid definition, following the same pattern as Agda standard library.
My trouble is that when I need a property of an algebraic structure that is deep within another one (e.g. property of a Monoid that is part of a CommutativeSemiring) we need to use a number of a projections equal to desired algebraic structure depth.
As an example of my problem, consider the following "lemma":
open import Algebra
open import Algebra.Structures
open import Data.Vec
open import Relation.Binary.PropositionalEquality
open import Algebra.FunctionProperties
open import Data.Product
module _ {Carrier : Set} {_+_ _*_ : Op₂ Carrier} {0# 1# : Carrier} (ICSR : IsCommutativeSemiring _≡_ _+_ _*_ 0# 1#) where
csr : CommutativeSemiring _ _
csr = record{ isCommutativeSemiring = ICSR }
zipWith-replicate-0# : ∀ {n}(xs : Vec Carrier n) → zipWith _+_ (replicate 0#) xs ≡ xs
zipWith-replicate-0# [] = refl
zipWith-replicate-0# (x ∷ xs) = cong₂ _∷_ (proj₁ (IsMonoid.identity (IsCommutativeMonoid.isMonoid
(IsCommutativeSemiring.+-isCommutativeMonoid
(CommutativeSemiring.isCommutativeSemiring csr)))) x)
(zipWith-replicate-0# xs)
Note that in order to access the left identity property of a monoid, I need to project it from the monoid that is within the commutative monoid that lies in the structure of an commutative semiring.
My concern is that, as I add more and more algebraic structures, such lemmas it will become unreadable.
My question is: Is there a pattern or trick that can avoid this "ladder" of record projections?
Any clue on this is highly welcome.
If you look at the Agda standard library, you'll see that for most specialized algebraic structures, the record defining them has the less specialized structure open public. E.g. in Algebra.AbelianGroup, we have:
record AbelianGroup c ℓ : Set (suc (c ⊔ ℓ)) where
-- ... snip ...
open IsAbelianGroup isAbelianGroup public
group : Group _ _
group = record { isGroup = isGroup }
open Group group public using (setoid; semigroup; monoid; rawMonoid)
-- ... snip ...
So an AbelianGroup record will have not just the AbelianGroup/IsAbelianGroup fields available, but also setoid, semigroup and monoid and rawMonoid from Group. In turn, setoid, monoid and rawMonoid in Group come from similarly open public-reexporting these fields from Monoid.
Similarly, for algebraic property witnesses, they re-export the less specialized version's fields, e.g. in IsAbelianGroup we have
record IsAbelianGroup
{a ℓ} {A : Set a} (≈ : Rel A ℓ)
(∙ : Op₂ A) (ε : A) (⁻¹ : Op₁ A) : Set (a ⊔ ℓ) where
-- ... snip ...
open IsGroup isGroup public
-- ... snip ...
and then IsGroup reexports IsMonoid, IsMonoid reexports IsSemigroup, and so on. And so, if you have IsAbelianGroup open, you can still use assoc (coming from IsSemigroup) without having to write out the whole path to it by hand.
The bottom line is you can write your function as follows:
open CommutativeSemiring CSR hiding (refl)
open import Function using (_⟨_⟩_)
zipWith-replicate-0# : ∀ {n}(xs : Vec Carrier n) → zipWith _+_ (replicate 0#) xs ≡ xs
zipWith-replicate-0# [] = refl
zipWith-replicate-0# (x ∷ xs) = proj₁ +-identity x ⟨ cong₂ _∷_ ⟩ zipWith-replicate-0# xs

Creating a Visitor Pattern with Polymorphic Recursive Modules

(Disclaimer: I am fairly certain that this is not idiomatic in any way. If there is some alternative tree-traversal idiom in OCaml, I'm all ears :) )
I am writing a toy compiler in OCaml, and I would like to have a visitor for my large syntax tree type. I wrote one using classes, but I thought it would be fun to try and implement one using modules/functors. My type hierarchy is massive, so let me illustrate what I'm trying to do.
Consider the following type definitions (making these up on the spot):
type expr =
SNum of int
| SVarRef of string
| SAdd of expr * expr
| SDo of stmt list
and stmt =
SIf of expr * expr * expr
| SAssign of string * expr
Let me briefly illustrate usage. Say, for example, I wanted to collect all of the SVarRefs inside of the program. If I had a mapping visitor (one which visits every node of the tree and does nothing by default), I could do the following (in a perfect world):
module VarCollector : (sig
include AST_VISITOR
val var_refs : (string list) ref
end) = struct
include MapVisitor
let var_refs = ref []
let s_var_ref (s : string) =
var_refs := s::!var_refs
SVarRef(s)
end
(* Where my_prog is a stmt type *)
let refs = begin
let _ = VarCollector.visit_stmt my_prog in
VarCollector.!var_refs
end
I should note that the advantage of having functions for each specific variant is that my actual codebase has a type which both has a large amount of variants and does not make sense to fragment. Variant-specific functions allow the avoiding of repeated iteration implementations for the other variants of a type.
Seems simple enough, but here's the catch: there are different types of visitors. MapVisitor returns the original syntax tree, so it has type
sig
(** Dispatches to variant implementations *)
val visit_stmt : stmt -> stmt
val visit_expr : expr -> expr
(** Variant implementations *)
val s_num : int -> expr
val s_var_ref : string -> expr
val s_add : (expr * expr) -> expr
val s_do : stmt list -> expr
val s_if : (expr * expr * expr) -> stmt
val s_assign : (string * expr) -> stmt
end
At the same time, one might imagine a folding visitor in which the return type is some t for every function. Attempting to abstract this as much as possible, here is my attempt:
module type AST_DISPATCHER = sig
type expr_ret
type stmt_ret
val visit_expr : expr -> expr_ret
val visit_stmt : stmt -> stmt_ret
end
(** Concrete type designation goes in AST_VISITOR_IMPL *)
module type AST_VISITOR_IMPL = sig
type expr_ret
type stmt_ret
val s_num : int -> expr_ret
val s_var_ref : string -> expr_ret
val s_add : (expr * expr) -> expr_ret
val s_do : stmt list -> expr_ret
val s_if : (expr * expr * expr) -> stmt_ret
val s_assign : (string * expr) -> stmt_ret
end
module type AST_VISITOR = sig
include AST_VISITOR_IMPL
include AST_DISPATCHER with type expr_ret := expr_ret
and type stmt_ret := stmt_ret
end
(** Dispatcher Implementation *)
module AstDispatcherF(IM : AST_VISITOR_IMPL) : AST_DISPATCHER = struct
type expr_ret = IM.expr_ret
type stmt_ret = IM.stmt_ret
let visit_expr = function
| SNum(i) -> IM.s_num i
| SVarRef(s) -> IM.s_var_ref s
| SAdd(l,r) -> IM.s_add (l,r)
| SDo(sl) -> IM.s_do sl
let visit_stmt = function
| SIf(c,t,f) -> IM.s_if (c,t,f)
| SAssign(s,e) -> IM.s_assign (s,e)
end
module rec MapVisitor : AST_VISITOR = struct
type expr_ret = expr
type stmt_ret = stmt
module D : (AST_DISPATCHER with type expr_ret := expr_ret
and type stmt_ret := stmt_ret)
= AstDispatcherF(MapVisitor)
let visit_expr = D.visit_expr
let visit_stmt = D.visit_stmt
let s_num i = SNum i
let s_var_ref s = SVarRef s
let s_add (l,r) = SAdd(D.visit_expr l, D.visit_expr r)
let s_do sl = SDo(List.map D.visit_stmt sl)
let s_if (c,t,f) = SIf(D.visit_expr c, D.visit_expr t, D.visit_expr f)
let s_assign (s,e) = SAssign(s, D.visit_expr e)
end
Running this gives me the following error message, however:
Error: Signature Mismatch:
Values do not match:
val visit_expr : expr -> expr_ret
is not included in
val visit_expr : expr -> expr_ret
I know this means that I am not expressing the relationship between the types correctly, but I cannot figure out what the fix is in this case.
Disclaimer: Modules are just records of values accompanied with type definitions. Since there are no types in your modules there is no need to use them at all, just use plain old record types, and you will get one of the idiomatic AST traversal pattern. Soon, you will find out that you need an open recursion, and will switch to class-based approach. Anyway, this was the main reason, why classes were added to OCaml. You may also wrap your classes into a state monad, to fold AST with arbitrary user data.
What concerning your error message, then it is simple, you hide your types with signatures, a common mistake. The easiest solution is to omit an annotation of the return type of a functor at all, or to propagate type equality with a with type expr = expr annotations.
If you need examples of more idiomatic approaches, then for records you can go for ppx mappers, here is an example of different visitors implemented with classes, including those that are wrapped into a state monad.

Coq - fold and maps on record types

I had previously posted problems like the following, but have not yet found a solution. I am having a store (mapping) from a record type (with five members) to a string value. A fold with a function guarding on the three elements of the record and returns a mapping (string to string). I need to solve some lemmas like gsc_MapsTo_iff_right below.
The code may contain some awkward syntax (for example fold) as I am not expert of Coq. Sorry for that.
Thank you for your help.
Wilayat
Require String.
Record c_id : Type := build_c_id {
c_id_d : String.string;
c_id_p : String.string;
c_id_s : bool;
c_id_h : bool;
c_id_k : String.string
}.
Definition skey := String.string.
Definition st (elt:Type) := list (String.string * elt).
Variable elt : Type.
Parameter Sadd : skey -> String.string -> st String.string -> st String.string.
Parameter SMapsTo : skey -> String.string -> st String.string -> Prop.
Definition ckey := c_id.
Definition ct (e:Type) := list (ckey * elt).
Implicit Type cm: ct elt.
Parameter Cadd : ckey -> String.string -> ct String.string -> st String.string.
Parameter CMapsTo : ckey -> String.string -> ct String.string -> Prop.
Parameter elements : ct String.string -> list (ckey*String.string).
Fixpoint rec_fold {A : Type} (f: ckey -> String.string -> A -> A) (l : list (ckey * String.string)) (b: A) : A :=
match l with
| nil => b
| cons (k, v) t => f k v (rec_fold f t b)
end.
Fixpoint fold {A: Type} (f: ckey -> String.string -> A -> A)
(cm: ct String.string) (b:A) : A :=
rec_fold f (elements cm) b.
Parameter empty : st String.string.
Axiom str_dec : forall a b : String.string, {a = b} + {a <> b}.
Definition str_eqdec (a b: String.string):bool :=
if str_dec a b then true else false.
Notation "x =?= y" := (str_eqdec x y) (at level 30).
Definition andb (b1 b2:bool) : bool := if b1 then b2 else false.
Notation "x & y" := (andb x y) (at level 40).
Definition get_sc (d p: String.string) (ckm: ct String.string)
: st String.string :=
fold
(fun cki v zm => if d =?= cki.(c_id_d) &
p =?= cki.(c_id_p) &
(negb (cki.(c_id_s)))
then Sadd cki.(c_id_k) v zm
else zm )
ckm
empty.
Lemma gsc_MapsTo_iff_right:
forall p d zk zv zh cm,
CMapsTo (build_c_id d p false zh zk) zv cm ->
SMapsTo zk zv (get_sc d p cm).
Proof.
Admitted.