What are the rules for custom syntax declarations in Agda? - syntax

The Agda docs don't really have much to say on syntax declarations, and a cursory glance at the source code is less than illuminating, so I've been trying to piece it together myself using examples from the standard library like Σ[_]_ and ∃[_]_. I can reproduce an (admittedly rather contrived) example like theirs fairly easily
twice : {A : Set} → (A → A) → A → A
twice f x = f (f x)
syntax twice (λ x → body) = twice[ x ] body
But when I try to define custom syntax that binds two variables, I get an error
swap : {A B C : Set} → (A → B → C) → B → A → C
swap f y x = f x y
syntax swap (λ x y → body) = swap[ x , y ] body
Specifically,
Parse error
y<ERROR>
→ body) = swap[ x , y ] body
...
So I assume there are some rules as to what's allowed on the left-hand side of a syntax declaration. What are these rules, and what of them prohibits my two-variable lambda form above?

Currently Agda does not allow syntax declarations with multi-argument lambda abstractions. This is a known limitation, see the issue tracker for the corresponding enhancement request.

Related

How do you use the Ring solver in Cubical Agda?

I have started playing around with Cubical Agda. Last thing I tried doing was building the type of integers (assuming the type of naturals is already defined) in a way similar to how it is done in classical mathematics (see the construction of integers on wikipedia). This is
data dInt : Set where
_⊝_ : ℕ → ℕ → dInt
canc : ∀ a b c d → a + d ≡ b + c → a ⊝ b ≡ c ⊝ d
trunc : isSet (dInt)
After doing that, I wanted to define addition
_++_ : dInt → dInt → dInt
(x ⊝ z) ++ (u ⊝ v) = (x + u) ⊝ (z + v)
(x ⊝ z) ++ canc a b c d u i = canc (x + a) (z + b) (x + c) (z + d) {! !} i
...
I am now stuck on the part between the two braces. A term of type x + a + (z + d) ≡ z + b + (x + c) is asked. Not wanting to prove this by hand, I wanted to use the ring solver made in Cubical Agda. But I could never manage to make it work, even trying to set it up for simple ring equalities like x + x + x ≡ 3 * x.
How can I make it work ? Is there a minimal example to make it work for naturals ? There is a file NatExamples.agda in the library, but it makes you have to rewrite your equalities in a convoluted way.
You can see how the solver for natural numbers is supposed to be used in this file in the cubical library:
Cubical/Tactics/NatSolver/Examples.agda
Note that this solver is different from the solver for commutative rings, which is designed for proving equations in abstract rings and is explained here:
Cubical/Tactics/CommRingSolver/Examples.agda
However, if I read your problem correctly, the equality you want to prove requires the use of other propositional equalities in Nat. This is not supported by any solver in the cubical library (as far as I know, also the standard library doesn't support it). But of course, you can use the solver for all the steps that don't use other equalities.
Just in case you didn't spot this: here is a definition of the integers in math-style using the SetQuotients of the cubical library. SetQuotients help you to avoid the work related to your third constructor trunc. This means you basically just need to show some constructions are well defined as you would in 'normal' math.
I've successfully used the ring solver for exactly the same problem: defining Int as a quotient of ℕ ⨯ ℕ. You can find the complete file here, the relevant parts are the following:
Non-cubical propositional equality to path equality:
open import Cubical.Core.Prelude renaming (_+_ to _+̂_)
open import Relation.Binary.PropositionalEquality renaming (refl to prefl; _≡_ to _=̂_) using ()
fromPropEq : ∀ {ℓ A} {x y : A} → _=̂_ {ℓ} {A} x y → x ≡ y
fromPropEq prefl = refl
An example of using the ring solver:
open import Function using (_$_)
import Data.Nat.Solver
open Data.Nat.Solver.+-*-Solver
using (prove; solve; _:=_; con; var; _:+_; _:*_; :-_; _:-_)
reorder : ∀ x y a b → (x +̂ a) +̂ (y +̂ b) ≡ (x +̂ y) +̂ (a +̂ b)
reorder x y a b = fromPropEq $ solve 4 (λ x y a b → (x :+ a) :+ (y :+ b) := (x :+ y) :+ (a :+ b)) prefl x y a b
So here, even though the ring solver gives us a proof of _=̂_, we can use _=̂_'s K and _≡_'s reflexivity to turn that into a path equality which can be used further downstream to e.g. prove that Int addition is representative-invariant.

Law of excluded middle in Agda

I've heard the claim that Agda's Martin-Lof Type Theory with Excluded Middle is consistent. How would I go about adding it as a postulate? Also, after Adding LEM, is it then classical first-order logic? By this I mean, do I also have the not (for all) = there exist (not) equivalence? I don't know type theory, so please add additional explanation if you quote any results in type theory.
In MLTT, exists corresponds to a dependent pair which is defined in Data.Product in the standard library. It packages together the existence witness and the proof that it has the right property.
It is not necessary to postulate anything to prove that the negation of an existential statement implies the universal statement of the negated property:
∄⇒∀ : {A : Set} {B : A → Set} →
¬ (∃ λ a → B a) →
∀ a → ¬ (B a)
∄⇒∀ ¬∃ a b = ¬∃ (a , b)
To prove the converse however you do need the law of excluded middle to have a witness appear out of thin air. It is really easy to extend Agda with new postulates, you can simply write (Dec is defined in Relation.Nullary):
postulate LEM : (A : Set) → Dec A
It's always a good thing to remember how to prove double-negation elimination starting from LEM and we will need later on anyway so there it is (case_of_ is defined in Function and explained in README.Case):
¬¬A⇒A : {A : Set} → ¬ (¬ A) → A
¬¬A⇒A {A} ¬¬p =
case LEM A of λ
{ (yes p) → p
; (no ¬p) → ⊥-elim $ ¬¬p ¬p
}
And you can then prove that the negation of a universal statement implies an
existential one like so:
¬∀⇒∃ : {A : Set} {B : A → Set} →
¬ (∀ a → B a) →
∃ λ a → ¬ (B a)
¬∀⇒∃ {A} {B} ¬∀ =
case LEM (∃ λ a → ¬ B a) of λ
{ (yes p) → p
; (no ¬p) → ⊥-elim $ ¬∀ (¬¬A⇒A ∘ ∄⇒∀ ¬p)
}
A gist with all the right imports

Realising level polymorphic subsets within records

Using the notion of subsets as predicates,
ℙ : ∀ {b a} → Set a → Set (a ⊔ suc b)
ℙ {b} {a} X = X → Set b
I'd like to consider structures endowed with a predicate on subsets,
record SetWithAPredicate {a c} : Set {!!} where
field
S : Set a
P : ∀ {b} → ℙ {b} S → Set c
This is an ill-formed construction due to the level quantification used in ℙ. Everything works fine when I use S, P as parameters to a module, but I'd like them to be records so that I can form constructions on them and give instances of them.
I've tried a few other things, such as moving the level b of ℙ inside the definition via an existential but then that led to metavaraible trouble. I also tried changing the type of P,
P : ℙ {a} S → Set c
but then I can no longer ask for, say, the empty set to have the property:
P-⊥ : P(λ _ → ⊥)
This is not well typed since Set != Set a ---I must admit, I tried to use Level.lift here, but failed to do so.
More generally, this will also not allow me to express closure properties, such as P is closed under arbitrary unions ---this is what I'm really interested in.
I understand that I can just avoid level polymorphism,
ℙ' : ∀ {a} → Set a → Set (suc zero ⊔ a)
ℙ' {a} X = X → Set
but then simple items such as the largest subset,
ℙ'-⊤ : ∀ {i} {A : Set i} → ℙ' A
ℙ'-⊤ {i} {A} = λ e → Σ a ∶ A • a ≡ e
-- Σ_∶_•_ is just syntax for Σ A (λ a → ...)
will not even typecheck!
Perhaps I did not realise the notion of subset as predicate appropriately ---any advice would be appreciated. Thank-you!
You need to lift b out from P like this
record SetWithAPredicate {a c} b : Set {!!} where
field
S : Set a
P : ℙ {b} S → Set c
Yes, this is ugly and annoying, but that's how it's done in Agda (an example from standard library: _>>=_ is not properly universe polymorphic). Lift can help sometimes, but it quickly gets out of hand.
Perhaps I did not realise the notion of subset as predicate
appropriately ---any advice would be appreciated.
Your definition is correct, but there is another one, see 4.8.3 in Conor McBride's lecture notes.

Understanding the syntax of Agda

Using the following as an example
postulate DNE : {A : Set} → ¬ (¬ A) → A
data ∨ (A B : Set) : Set where
inl : A → A ∨ B
inr : B → A ∨ B
-- Use double negation to prove exclude middle
classical-2 : {A : Set} → A ∨ ¬ A
classical-2 = λ {A} → DNE (λ z → z (inr (λ x → z (inl x)))
I know this is correct, purely because of how agda works, but I am new to this language and can't get my head around how its syntax works, I would appreciate if anyone can walk me through what is going on, thanks :)
I have experience in haskell, although that was around a year ago.
Let's start with the postulate. The syntax is simply:
postulate name : type
This asserts that there exists some value of type type called name. Think of it as axioms in logic - things that are defined to be true and are not be questioned (by Agda, in this case).
Next up is the data definition. There's a slight oversight with the mixfix declaration so I'll fix it and explain what it does. The first line:
data _∨_ (A B : Set) : Set where
Introduces a new type (constructor) called _∨_. _∨_ takes two arguments of type Set and then returns a Set.
I'll compare it with Haskell. The A and B are more or less equivalent to a and b in the following example:
data Or a b = Inl a | Inr b
This means that the data definition defines a polymorphic type (a template or a generic, if you will). Set is the Agda equivalent of Haskell's *.
What's up with the underscores? Agda allows you to define arbitrary operators (prefix, postfix, infix... usually just called by a single name - mixfix). The underscores just tell Agda where the arguments are. This is best seen with prefix/postfix operators:
-_ : Integer → Integer -- unary minus
- n = 0 - n
_++ : Integer → Integer -- postfix increment
x ++ = x + 1
You can even create crazy operators such as:
if_then_else_ : ...
Next part is definition of the data constructors itself. If you've seen Haskell's GADTs, this is more or less the same thing. If you haven't:
When you define a constructor in Haskell, say Inr above, you just specify the type of the arguments and Haskell figures out the type of the whole thing, that is Inr :: b -> Or a b. When you write GADTs or define data types in Agda, you need to specify the whole type (and there are good reasons for this, but I won't get into that now).
So, the data definition specifies two constructors, inl of type A → A ∨ B and inr of type B → A ∨ B.
Now comes the fun part: first line of classical-2 is a simple type declaration. What's up with the Set thing? When you write polymorphic functions in Haskell, you just use lower case letters to represent type variables, say:
id :: a -> a
What you really mean is:
id :: forall a. a -> a
And what you really mean is:
id :: forall (a :: *). a -> a
I.e. it's not just any kind of a, but that a is a type. Agda makes you do this extra step and declare this quantification explicitly (that's because you can quantify over more things than just types).
And the curly braces? Let me use the Haskell example above again. When you use the id function somewhere, say id 5, you don't need to specify that a = Integer.
If you used normal paretheses, you'd have to provide the actual type A everytime you called classical-2. However, most of the time, the type can be deduced from the context (much like the id 5 example above), so for those cases, you can "hide" the argument. Agda then tries to fill that in automatically - and if it cannot, it complains.
And for the last line: λ x → y is the Agda way of saying \x -> y. That should explain most of the line, the only thing that remains are the curly braces yet again. I'm fairly sure that you can omit them here, but anyways: hidden arguments do what they say - they hide. So when you define a function from {A} to B, you just provide something of type B (because {A} is hidden). In some cases, you need to know the value of the hidden argument and that's what this special kind of lambda does: λ {A} → allows you to access the hidden A!

Custom Isabelle syntax breaks existing syntax

I am attempting to generate a nice syntax for mapping a function over the values of an associative list, i.e. I want to write [x ↦ f y | (x ↦ y) ∈ l] for mapAList f l. I came up with
syntax
"_alist_map" :: "['b, pttrn, ('a × 'b) list] ⇒ ('a × 'b) list"
("[x ↦ _ | '(x ↦ _') ∈ _]")
which works, but causes term "(x,y)#[]" to tell me Inner syntax error at "(x , y ) # []" and the (x is shaded slightly different.
The reason seems that once x appears in a mixfix annotation, it now always a literal token to the grammer (a delimiter according to §7.4.1 of isar-ref) and no longer an identifier – just like the syntax for if ... then ... else ... prevents if from being a variable name
Can I somehow work around this problem?
Identifier names used in mixfix annotations cannot be used as identifiers any longer, and I don't know any way around that. Therefore, instead of using x as a variable name, you can pick a non-identifier symbol like \<xX> or \<mapAListvariable> and setup the LaTeX output to print this as x by adding \newcommand{\isasymmapAListvariable}{x} to your root.tex.
You can also add \<xX> or \<mapAListvariable> to the symbols file of Isabelle/JEdit (preferably in $ISABELLE_HOME_USER/etc/symbols) and assign it some Unicode point that will be used for display in Isabelle/JEdit.
I just made a small experiment with a function map_alist that hopefully corresponds to your mapAList and which is defined as follows:
fun map_alist :: "('b ⇒ 'c) ⇒ ('a × 'b) list ⇒ ('a × 'c) list"
where
"map_alist f [] = []" |
"map_alist f ((x, y) # xs) = (x, f y) # map_alist f xs"
Then existing syntax can be used which looks a little bit as you intended. Maybe this is an option?
lemma "map_alist f xs = [(x, f y). (x, y) ← xs]"
by (induct xs) auto

Resources