Indexed family of binary operators with infix notation - macros

Suppose you want to define a family of binary operators (indexed by sets, say) where the types of the arguments depends on the value of the index, and the index is passed explicitly. In addition, suppose you would like a member of the family to be usable in infix notation:
x <[A] y
A here is the index; the brackets [-] are supposed to indicate that A should be read as a subscript. Giving a type signature for such an operation compatible with this syntax is difficult because the type of x depends on the value A, and so A : Set must occur to the left of x : A in the definition of _<[_]_.
I've experimented with the following trick (hack?) based on syntax declarations:
cmp : (A : Set) → A → A → Set
cmp = {!!}
syntax cmp A x y = x <[ A ] y
postulate C : Set
postulate c : C
x = c <[ C ] c
This seems to work, unless your binary operation uses implicit instances. If I try to add arguments of the form {{x}} to a syntax declaration, Agda complains. (Not unreasonably, perhaps.)
It seems one can adapt the idiom by introducing a version of cmp which takes the implicit instance explicitly, and then define a variant of the syntax which invokes that version:
postulate B : Set
-- Now expects an ambient B.
cmp : (A : Set) {{b : B}} → A → A → Set
cmp = {!!}
-- Version of cmp that makes implicit instance explicit.
cmp-explicit : (A : Set) (b : B) → A → A → Set
cmp-explicit A b = cmp A {{b}}
syntax cmp A x y = x <[ A ] y
syntax cmp-explicit A b x y = x <[ A at b ] y
postulate C : Set
postulate c : C
postulate b : B
x = c <[ C ] c -- pick up ambient B
y = c <[ C at b ] c -- pass B explicitly
(Since syntax doesn't appear to support {{x}} arguments, one cannot just inline cmp into cmp-explicit, without giving up the ability to pick up an ambient B entirely.)
Is this a hack? Is there another way to flip arguments x and y when the type of y depends on the value of x, and x is passed explicitly?
Naturally, defining
_<′[_]_ = λ x A y → cmp A x y
causes Agda to complain when typechecking x.

You can't really flip the arguments in a way that A : Set comes after x : A.
You already mentioned syntax, which I think is the best solution. This works because Agda will transform x <[ A ] y into cmp A x y and that's fine with the type checker.
Here's another (rather ugly and hacky) approach. Let's say we have:
_<[_]_ : {A : Set} → A → ? → A → Set
Here we can exploit unification a bit: by using something that mentions A in the ? hole, we can force the type checker to fill in the implicit A in front. But as far as I know, there's no simple type we can use in place of ?, so that we get the required x <[ A ] y. But to finish the thought, here's one thing that works:
data Is : Set → Set₁ where
is : (A : Set) → Is A
_<[_]_ : {A : Set} → A → Is A → A → Set
x <[ is A ] y = cmp A x y
Yes, this is fairly ugly and I would recommend against it.
But back to your question about syntax: I would not consider syntax to be a hack in any way. In fact, the standard library uses syntax in roughly the same way in one place (Data.Plus to be exact):
syntax Plus R x y = x [ R ]⁺ y
Even having cmp-explicit around is useful. I would even go as far as to suggest you make two extra versions:
cmp-syntax = cmp
cmp-explicit-syntax = λ A b → cmp A {{b}}
syntax cmp-syntax A x y = x <[ A ] y
syntax cmp-explicit-syntax A b x y = x <[ A at b ] y
If the user of your module does not want to use the syntactic shortcut (for example, he imports another module that defines _<[_]_), he can simply choose to not import it and still have cmp around.
Again, standard library does this with the syntactic shortcut for Σ. The shortcut allows you to write:
open import Data.Nat
open import Data.Product
open import Relation.Binary.PropositionalEquality
x : Σ[ n ∈ ℕ ] n + 2 ≡ 4
x = 2 , refl
And if you do not want it, then you simply:
open import Data.Product
hiding (Σ-syntax)

Related

Define a function based on a relation in Coq

I'm working on a theory in which there is a relation C defined as
Parameter Entity: Set.
Parameter C : Entity -> Entity -> Entity -> Prop.
The relation C is a relation of composition of some entities. Instead of C z x y, I want to be able to write x o y = z. So I have two questions:
I think I should define a "function" (the word is perhaps not the right one) named fC that takes x and y and returns z. This way, I could use it in the Notation. But I don't know how to define this "function". Is it possible?
I find that I can use the command Notation to define an operator. Something like Notation "x o y" := fC x y.. Is this the good way to do it?
I tried Notation "x o y" := exists u, C u x y. but it didn't work. Is there a way to do what I want to do?
Unless your relation C has the property that, given x and y, there is a unique z such that C z x y, you cannot view it as representing a full-fledged function the way you suggest. This is why the notion of a relation is needed in that case.
As for defining a notation for the relation property, you can use:
Notation "x 'o y" := (exists u, C u x y) (at level 10).
Note the ' before the o to help the parser handle the notation and the parentheses after the := sign. The level can be changed to suit your parsing preferences.
If you define x 'o y as a proposition, you will lose the intuition of o being a binary operation on Entity (i.e x o y should have type Entity).
You may write some variation like
Notation "x 'o y '= z" := (unique (fun t => C t x y)) (at level 10).
Otherwise, If your relation satisfies:
Hypothesis C_fun: forall x y, {z : Entity | unique (fun t => C t x y) z}.
then you may define:
Notation "x 'o y" := (proj1_sig (C_fun x y)) (at level 10).
Check fun a b: Entity => a 'o b.
Otherwise (if you have only have a weaker version of C_fun, with existsinstead of sig) and accept to use classical logic and axioms), you may use the Epsilon operator
https://coq.inria.fr/distrib/current/stdlib/Coq.Logic.ClassicalEpsilon.html

Use condition in a ssreflect finset comprehension

I have a function f that takes a x of fintype A and a proof of P x to return an element of fintype B. I want to return the finset of f x for all x satisfying P, which could be written like this :
From mathcomp
Require Import ssreflect ssrbool fintype finset.
Variable A B : finType.
Variable P : pred A.
Variable f : forall x : A, P x -> B.
Definition myset := [set (#f x _) | x : A & P x].
However, this fails as Coq does not fill the placeholder with the information on the right, and I do not know how to provide it explicitly.
I did not find an indication on how to do that, both in the ssreflect code and book. I realize that I could probably do it by using a sigma-type {x : A ; P x} and modifying a bit f, but it feels more convoluted than it should. Is there a simple / readable way to do that ?
Actually the easiest way to make things work in the way you propose is to use a sigma type:
Definition myset := [set f (tagged x) | x : { x : A | P x }].
But indeed, f is a bit of a strange function, I guess we'll need to know more details about your use case to understand where are you going.

Messing around with category theory

Motivation: I am attempting to study category theory while creating a Coq formalization of the ideas I find in whatever textbook I follow. In order to make this formalization as simple as possible, I figured I should identify objects with their identity arrow, so a category can be reduced to a set (class, type) of arrows X with a source mapping s:X->X, target mapping t:X->X, and composition mapping product : X -> X -> option X which is a partial mapping defined for t f = s g. Obviously the structure (X,s,t,product) should follow various properties. For the sake of clarity, I am spelling out the formalization I chose below, but there is no need to follow it I think in order to read my question:
Record Category {A:Type} : Type := category
{ source : A -> A
; target : A -> A
; product: A -> A -> option A
; proof_of_ss : forall f:A, source (source f) = source f
; proof_of_ts : forall f:A, target (source f) = source f
; proof_of_tt : forall f:A, target (target f) = target f
; proof_of_st : forall f:A, source (target f) = target f
; proof_of_dom: forall f g:A, target f = source g <-> product f g <> None
; proof_of_src: forall f g h:A, product f g = Some h -> source h = source f
; proof_of_tgt: forall f g h:A, product f g = Some h -> target h = target g
; proof_of_idl: forall a f:A,
a = source a ->
a = target a ->
a = source f ->
product a f = Some f
; proof_of_idr: forall a f:A,
a = source a ->
a = target a ->
a = target f ->
product f a = Some f
; proof_of_asc:
forall f g h fg gh:A,
product f g = Some fg ->
product g h = Some gh ->
product fg h = product f gh
}
.
I have no idea how practical this is and how far it will take me. I see this as an opportunity to learn category theory and Coq at the same time.
Problem: My first objective was to create a 'Category' which would resemble as much as possible the category Set. In a set theoretic framework, I would probably consider the class of triplets (a,b,f) where f is a map with domain a and range a subset of b. With this in mind I tried:
Record Arrow : Type := arrow
{ dom : Type
; cod : Type
; arr : dom -> cod
}
.
So that Arrow becomes my base type on which I could attempt building a structure of category. I start embedding Type into Arrow:
Definition id (a : Type) : Arrow := arrow a a (fun x => x).
which allows me to define the source and target mappings:
Definition domain (f:Arrow) : Arrow := id (dom f).
Definition codomain (f:Arrow) : Arrow := id (cod f).
Then I move on to defining a composition on Arrow:
Definition compose (f g: Arrow) : option Arrow :=
match f with
| arrow a b f' =>
match g with
| arrow b' c g' =>
match b with
| b' => Some (arrow a c (fun x => (g' (f' x))))
| _ => None
end
end
end.
However, this code is illegal as I get the error:
The term "f' x" has type "b" while it is expected to have type "b'".
Question: I have the feeling I am not going to get away with this, My using Type naively would take me to some sort of Russel paradox which Coq will not allow me to do. However, just in case, is there a way to define compose on Arrow?
Your encoding does not work in plain Coq because of the constructive nature of the theory: it is not possible to compare two sets for equality. If you absolutely want to follow this approach, Daniel's comment sketches a solution: you need to assume a strong classical principle to be able to check whether the endpoints of two arrows match, and then manipulate an equality proof to make Coq accept the definition.
Another approach is to have separate types for arrows and objects, and use type dependency to express the compatibility requirement on arrow endpoints. This definition requires only three axioms, and considerably simplifies the construction of categories:
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Record category : Type := Category {
obj : Type;
hom : obj -> obj -> Type;
id : forall {X}, hom X X;
comp : forall X Y Z, hom X Y -> hom Y Z -> hom X Z;
(* Axioms *)
idL : forall X Y (f : hom X Y), comp id f = f;
idR : forall X Y (f : hom X Y), comp f id = f;
assoc : forall X Y Z W
(f : hom X Y) (g : hom Y Z) (h : hom Z W),
comp f (comp g h) = comp (comp f g) h
}.
We can now define the category of sets and ask Coq to automatically prove the axioms for us.
Require Import Coq.Program.Tactics.
Program Definition Sets : category := {|
obj := Type;
hom X Y := X -> Y;
id X := fun x => x;
comp X Y Z f g := fun x => g (f x)
|}.
(This does not lead to any circularity paradoxes, because of Coq's universe mechanism: Coq understands that the Type used in this definition is actually smaller than the one used to define category.)
This encoding is sometimes inconvenient due to the lack of extensionality in Coq's theory, because it prevents certain axioms from holding. Consider the category of groups, for example, where the morphisms are functions that commute with the group operations. A reasonable definition for these morphisms could be as follows (assuming that there is some type group representing groups, with * denotes multiplication and 1 denotes the neutral element).
Record group_morphism (X Y : group) : Type := {
mor : X -> Y;
mor_1 : mor 1 = 1;
mor_m : forall x1 x2, mor (x1 * x2) = mor x1 * mor x2
}.
The problem is that the properties mor_1 and mor_m interfere with the notion of equality for elements of group_morphism, making the proofs for associativity and identity that worked for Sets break. There are two solutions:
Adopt extra axioms into the theory so that the required properties still go through. In the above example, you would need proof irrelevance:
proof_irrelevance : forall (P : Prop) (p q : P), p = q.
Change the category axioms so that the identities are valid up to some equivalence relation specific to that category, instead of the plain Coq equality. This approach is followed here, for example.

How to get syntax declarations to be used by case splitting

I would like to automatically case over arguments using a syntax declared
besides the one given as a type constructor. For example,
postulate P : ℕ → ℕ → Set
data Silly : Set where
goo : (n : ℕ) → Fin n → (m : ℕ) → Fin m → P n m → Silly
Here, I'd like to have the proof P n m occur between the n and m arguments, but that cannot be since both need to be declare for it to be expressed. Hence, we use a syntax declaration:
syntax goo n i m j pf = i ⟵[ n , pf , m ]⟶ j
Now, we can write-up by-hand
want-to-use-syntax-in-pattern-matching : Silly → Set
want-to-use-syntax-in-pattern-matching (i ⟵[ n , pf , m ]⟶ j) = ℕ
This works fine, but when I case-split via C-c C-c, it uses goo instead of my syntax. Is there any way to make case splitting use my declared syntax ?
(
Incidentally, using
syntax goo n i m j pf = i ─[ n , pf , m ]⟶ j
fails, where ─ is produced by \---
)
Nowadays Agda resugars patterns on the left if they are in scope unqualified
so this would just work.

Type hierarchy definition in Coq or Agda

I would like to build a kind of type hierarchy:
B is of type A ( B::A )
C and D are of type of B (C,D ::B)
E and F are of type of C (E,F ::C)
I asked here if this is possible to be directly implemented in Isabelle, but the answer as you see was No. Is it possible to encode this directly in Agda or Coq?
PS: Suppose A..F are all abstract and some functions are defined over each type)
Thanks
If I understood your question correctly, you want something that looks like the identity type. When we declare the type constructor _isOfType_, we mention two Sets (the parameter A and the index B) but the constructor indeed makes sure that the only way to construct an element of such a type is to enforce that they are indeed equal (and that a is of this type):
data _isOfType_ {ℓ} {A : Set ℓ} (a : A) : (B : Set ℓ) → Set where
indeed : a isOfType A
We can now have functions taking as arguments proofs that things are of the right type. Here I translated your requirements & assumed that I had a function f able to combine two Cs into one. Pattern-matching on the appropriate assumptions reveals that E and F are indeed on type C and can therefore be fed to f to discharge the goal:
example : ∀ (A : Set₃) (B : Set₂) (C D : Set₁) (E F : Set) →
B isOfType A
→ C isOfType B → D isOfType B
→ E isOfType C → F isOfType C
→ (f : C → C → C) → C
example A B .Set D E F _ _ _ indeed indeed f = f E F
Do you have a particular use case in mind for this sort of patterns or are you coming to Agda with ideas you have encountered in other programming languages? There may be a more idiomatic way to formulate your problem.