How to make Agda pretty-print products nicely - agda

Consider the following self-contained program:
module Test where
record Σ {A : Set} (B : A -> Set) : Set where
constructor _,_
field
fst : A
snd : B fst
open Σ public
infixr 0 _,_
_×_ : Set -> Set -> Set
A × B = Σ (\ (_ : A) -> B)
infixr 10 _×_
f : {A B : Set} → A × B → A
f x = {!!}
If you C-c C-l in the goal, you get:
Goal: .A
————————————————————————————————————————————————————————————
x : Σ (λ _ → .B)
.B : Set
.A : Set
i.e. you see the underlying sigma, and the type of the binder of the lambda is hidden. This is pretty annoying. Is there a way to make Agda show the type of binders that don't bind names by default?
This is Agda 2.3.2.2.

Agda 2.4.3 displays x : .A × .B.
You can use the abstract keyword:
abstract
_×_ : Set -> Set -> Set
A × B = Σ (\ (_ : A) -> B)
fst' : ∀ {A B} -> A × B -> A
fst' (x , y) = x
snd' : ∀ {A B} -> A × B -> B
snd' (x , y) = y
But that's definitely overkill (and it looks like pattern synonyms do not work in abstract blocks).
It's much more annoying to me, that Agda doesn't want to reduce functions like flip and especially _∘_, but unfolds some functions with really long definitions. Agda needs a mechanism for fixing these problems.

It appears that this problem has been fixed in the latest version of Agda, so you should upgrade.

Related

About the image of the succ function

I defined the natural numbers as usually:
data Nat : Set where
zero : Nat
succ : Nat → Nat
and i.e the number one should be
one : Nat
one = succ zero
Later on, we can define the image datatype,
data Image_∋_ {A B : Set} (f : A → B) : B -> Set where
im : (x : A) → Image f ∋ (f x)
And to prove something like "the one is in the Image of the successor function" I wrote:
one-succ : Image succ ∋ one
one-succ = im zero
I would like to have the following.
Define the predecessor function that not allowed zero as an input just its successors. So the next is not valid.
pred : Nat → Nat
pred zero = zero
pred (succ n) = n
I would like to have a variable called Z⁺ representing the positive numbers but using in its definition the image of successor function (Image_∋_ data type defined above).
Image f ∋ y reads as "there is some x such that y ≡ f x". Pattern matching on Image f ∋ y by im x reveals the x.
So an element of type Image succ ∋ n is a proof that n is of the form succ m where m is carried inside that element. Hence the definition is simply
ipred : ∀ {n} → Image succ ∋ n → Nat
ipred (im m) = m
because n ≡ succ m and the predecessor of succ m is m.
It reads nicer if we rename im to isucc:
open Image_∋_ renaming (im to isucc)
ipred : ∀ {n} → Image succ ∋ n → Nat
ipred (isucc m) = m
Another way of writing the same thing is
data Image_∋_ {A B : Set} : (A → B) → B → Set where
_·_ : (f : A → B) → (x : A) → Image f ∋ f x
pred : ∀ {n} → Image succ ∋ n → Nat
pred (.succ · m) = m
Here f in Image f ∋ y is an index rather than a parameter, so _·_ (previously im) now receives two arguments: a function and its argument. It's not possible to pattern match on functions, but .succ is an "irrefutable pattern", i.e. it says "f can be nothing, but succ".
Nat⁺ can be defined as
data Nat⁺ : Set where
nat⁺ : ∀ {n} → Image succ ∋ n → Nat⁺
succ⁺ receives a natural number (implicitly) and a proof that this number is of the form succ m for some m.
You can always take the predecessor of a positive natural number:
pred⁺ : Nat⁺ → Nat
pred⁺ (nat⁺ (im m)) = m
But since Nat⁺ is a non-indexed one-constructor data type, it can be defined as a record:
record Nat⁺ : Set where
constructor nat⁺
field
{pred⁺} : Nat
image : Image succ ∋ pred⁺
open Nat⁺
open Nat⁺ introduces pred⁺ : Nat⁺ → Nat in scope.

Modeling System F's parametric polymorphism at Set₀

In System F, the kind of a polymorphic type is * (as that's the only kind in System F anyway...), so e.g. for the following closed type:
[] ⊢ (forall α : *. α → α) : *
I would like to represent System F in Agda, and because everything is in *, I thought I'd interpret types (like the above) as Agda Sets; so something like
evalTy : RepresentationOfAWellKindedClosedType → Set
However, Agda doesn't have polymorphic types, so the above type, in Agda, would need to be a (large!) Π type:
idType = (α : Set) → α → α
which means it is not in Set₀:
idType : Set
idType = (α : Set) → α → α
poly-level.agda:4,12-29
Set₁ != Set
when checking that the expression (α : Set) → α → α has type Set
Is there a way out of this, or is System F not embeddable in this sense into Agda?
Instead of
evalTy : Type → Set
you can write
evalTy : (σ : Type) -> Set (levelOf σ)
(András Kovács, care to add an answer with references to your embedding of predicative System F?)
This is enough for embedding, but I've seen a lot of Setω errors and they have traumatised me, so now I'm trying to avoid dependent universes as much as possible.
You can embed polymorphic types into Set₁ and monomorphic types into Set, so you can embed any type into Set₁ using the ugly lifting mechanism. I tried this several times and it always was awful.
The thing I would try is to define evalTy as
evalTy : Type -> Set ⊎ Set₁
and then eliminate it at the type level like this:
data [_,_]ᵀ {α β γ δ} {A : Set α} {B : Set β} (C : A -> Set γ) (D : B -> Set δ)
: A ⊎ B -> Set (γ ⊔ δ) where
inj¹ : ∀ {x} -> C x -> [ C , D ]ᵀ (inj₁ x)
inj² : ∀ {y} -> D y -> [ C , D ]ᵀ (inj₂ y)
You can run this elimination:
Runᴸ : ∀ {α β γ δ} {A : Set α} {B : Set β} {C : A -> Set γ} {D : B -> Set δ} {s}
-> [ C , D ]ᵀ s -> Level
Runᴸ {γ = γ} (inj¹ _) = γ
Runᴸ {δ = δ} (inj² _) = δ
Runᵀ : ∀ {α β γ δ} {A : Set α} {B : Set β} {C : A -> Set γ} {D : B -> Set δ} {s}
-> (sᵀ : [ C , D ]ᵀ s) -> Set (Runᴸ sᵀ)
Runᵀ {C = C} (inj¹ {x} _) = C x
Runᵀ {D = D} (inj² {y} _) = D y
runᵀ : ∀ {α β γ δ} {A : Set α} {B : Set β} {C : A -> Set γ} {D : B -> Set δ} {s}
-> (sᵀ : [ C , D ]ᵀ s) -> Runᵀ sᵀ
runᵀ (inj¹ z) = z
runᵀ (inj² w) = w
Thus you introduce a universe dependency only at the end, when you actually need to compute something.
E.g.
SomeSet : ℕ -> Set ⊎ Set₁
SomeSet 0 = inj₁ ℕ
SomeSet n = inj₂ Set
ofSomeSet : ∀ n -> [ (λ A -> A × A) , id ]ᵀ (SomeSet n)
ofSomeSet zero = inj¹ (0 , 5)
ofSomeSet (suc n) = inj² ℕ
-- 0 , 5
test₁ : ℕ × ℕ
test₁ = runᵀ (ofSomeSet 0)
-- ℕ
test₂ : Set
test₂ = runᵀ (ofSomeSet 1)
ofSomeSet is a dependent function, but not a "universally dependent", you can write e.g. f = ofSomeSet ∘ suc and it's a perfectly typeable expression. This doesn't work with universes dependencies:
fun : ∀ α -> Set (Level.suc α)
fun α = Set α
oops = fun ∘ Level.suc
-- ((α : Level) → Set (Level.suc α)) !=< ((y : _B_160 .x) → _C_161 y)
-- because this would result in an invalid use of Setω
You can also enhance [_,_]ᵀ to make it mappable like I did here, but this all is probably overkill and you should just use
evalTy : (σ : Type) -> Set (levelOf σ)
Note that I'm talking only about the predicative fragment of System F. Full System F is not embeddable as Dominique Devriese explains in his comments to the question.
However I feel like we can embed more than the predicative fragment, if we first normalize a System F term. E.g. id [∀ α : *. α → α] id is not directly embeddable, but after normalization it becomes just id, which is embeddable.
However it should be possible to embed id [∀ α : *. α → α] id even without normalization by transforming it into Λ α. id [α → α] (id [α]), which is what Agda does with implicit arguments (right?). So it's not clear to me what exactly we can't embed.

universe quantification in agda

I could spot the problem and added universe quantification.
But if anyone can spell what is really going on, that would be interesting.
module Level0Equality (A : Set) where
data _Tauto'_ : A → A → Set where
refl2 : (a : A) → a Tauto' a
-- universe quantified
data _Tauto_ {l} {A : Set l} : A → A → Set l where
refl2 : (a : A) → a Tauto a
-- PEq x = the type of proof that y ≡ x
data PEq {A : Set} ( x : A ) : Set where
it : (y : A ) -> (y Tauto x ) -> PEq x
-- does not work because of lack of universe quantification in Tauto'
-- A !=< A of type Set
-- (because one has deBruijn index 2 and the other 3)
-- when checking that the expression y has type A
data PEq' {A : Set} ( x : A ) : Set where
it : (y : A ) -> (y Tauto' x ) -> PEq' x
The problem is that your definition of PEq' tells us that it works for any A from Set. However, _Tauto'_ only works for the one particular A that the user provides as the module parameter to Level0Equality.
Let me demonstrate it with an example:
open Level0Equality Bool
_Tauto'_ : Bool → Bool → Set
PEq' : {A : Set} → A → Set
Say we choose A = String, then we have:
PEq' {A = String} : String → Set
This will obviously cause problems in the PEq'.it constructor. The type of both x and y is now String, but the equality _Tauto'_ only works for Bools!
The fix is rather simple: use the A from the module telescope.
data PEq' ( x : A ) : Set where
it : (y : A ) -> (y Tauto' x ) -> PEq' x

How to define a singleton set?

Assume I have a value x : A and I want to define a set containing only x.
This is what I tried:
open import Data.Product
open import Relation.Binary.PropositionalEquality
-- Singleton x is the set that only contains x. Its values are tuples containing
-- a value of type A and a proof that this value is equal to x.
Singleton : ∀ {ℓ} {A : Set ℓ} → (x : A) → Set ℓ
Singleton {A = A} x = Σ[ y ∈ A ] (y ≡ x)
-- injection
singleton : ∀ {ℓ} {A : Set ℓ} → (x : A) → Singleton x
singleton x = x , refl
-- projection
fromSingleton : ∀ {ℓ} {A : Set ℓ} {x : A} → Singleton x → A
fromSingleton s = proj₁ s
Is there a better way to do it?
An example for why I want this: If you have a monoid over some set A, then you can form a category with A as the only object. To express that in Agda you need a way to write "the set containing only A".
I think this is a very good way to do it. Usually, when you want to create a "subset" of a type, it looks like:
postulate
A : Set
P : A → Set
record Subset : Set where
field
value : A
prop : P value
However, this might not be a subset in the sense that it can actually contain more elements than the original type. That is because prop might have more propositionally different values. For example:
open import Data.Nat
data ℕ-prop : ℕ → Set where
c1 : ∀ n → ℕ-prop n
c2 : ∀ n → ℕ-prop n
record ℕ-Subset : Set where
field
value : ℕ
prop : ℕ-prop value
And suddenly, the subset has twice as many elements as the original type. This example is a bit contrived, I agree, but imagine you had a subset relation on sets (sets from set theory). Something like this is actually fairly possible:
sub₁ : {1, 2} ⊆ {1, 2, 3, 4}
sub₁ = drop 3 (drop 4 same)
sub₂ : {1, 2} ⊆ {1, 2, 3, 4}
sub₂ = drop 4 (drop 3 same)
The usual approach to this problem is to use irrelevant arguments:
record Subset : Set where
field
value : A
.prop : P value
This means that two values of type Subset are equal if they have the same value, the prop field is irrelevant to the equality. And indeed:
record Subset : Set where
constructor sub
field
value : A
.prop : P value
prop-irr : ∀ {a b} {p : P a} {q : P b} →
a ≡ b → sub a p ≡ sub b q
prop-irr refl = refl
However, this is more of a guideline, because your representation doesn't suffer from this problem. This is because the implementation of pattern matching in Agda implies axiom K:
K : ∀ {a p} {A : Set a} (x : A) (P : x ≡ x → Set p) (h : x ≡ x) →
P refl → P h
K x P refl p = p
Well, this doesn't tell you much. Luckily, there's another property that is equivalent to axiom K:
uip : ∀ {a} {A : Set a} {x y : A} (p q : x ≡ y) → p ≡ q
uip refl refl = refl
This tells us that there's only one way in which two elements can be equal, namely refl (uip means uniqueness of identity proofs).
This means that when you use propositional equality to make a subset, you're getting a true subset.
Let's make this explicit:
isSingleton : ∀ {ℓ} → Set ℓ → Set _
isSingleton A = Σ[ x ∈ A ] (∀ y → x ≡ y)
isSingleton A expresses the fact that A contains only one element, up to propositonal equality. And indeed, Singleton x is a singleton:
Singleton-isSingleton : ∀ {ℓ} {A : Set ℓ} (x : A) →
isSingleton (Singleton x)
Singleton-isSingleton x = (x , refl) , λ {(.x , refl) → refl}
Interestingly, this also works without axiom K. If you put {-# OPTIONS --without-K #-} pragma at the top of your file, it will still compile.
You can define a record without projections:
record Singleton {α} {A : Set α} (x : A) : Set α where
fromSingleton : ∀ {α} {A : Set α} {x : A} -> Singleton x -> A
fromSingleton {x = x} _ = x
singleton : ∀ {α} {A : Set α} -> (x : A) -> Singleton x
singleton _ = _
Or equalently
record Singleton {α} {A : Set α} (x : A) : Set α where
fromSingleton = x
open Singleton public
singleton : ∀ {α} {A : Set α} -> (x : A) -> Singleton x
singleton _ = _
Now you can use it like this:
open import Relation.Binary.PropositionalEquality
open import Data.Nat
f : Singleton 5 -> ℕ
f x = fromSingleton x
test : f (singleton 5) ≡ 5
test = refl
test' : f _ ≡ 5
test' = refl
And this is rejected:
fail : f (singleton 4) ≡ 4
fail = ?
The error:
4 != 5 of type ℕ
when checking that the expression singleton 4 has type Singleton 5
It can be defined as an indexed datatype:
data Singleton {ℓ : _} {A : Set ℓ} : A -> Set where
singleton : (a : A) -> Singleton a
This is analogous to how propositional equality a ≡ b is indexed by two particular elements a and b, or how Vector X n is indexed by a particular n ∈ ℕ.

Instance Implicits for Type Checking

I am learning how "typeclasses" are implemented in Agda. As an example, I am trying to implement Roman numerals whose composition with # would type-check.
I am not clear why Agda complains there is no instance for Join (Roman _ _) (Roman _ _) _ - clearly, it couldn't work out what natural numbers to substitute there.
Is there a nicer way to introduce Roman numbers that don't have "constructor" form? I have a constructor "madeup", which probably would need to be private, to be sure I have only "trusted" ways to construct other Roman numbers through Join.
module Romans where
data ℕ : Set where
zero : ℕ
succ : ℕ → ℕ
infixr 4 _+_ _*_ _#_
_+_ : ℕ → ℕ → ℕ
zero + x = x
succ y + x = succ (y + x)
_*_ : ℕ → ℕ → ℕ
zero * x = zero
succ y * x = x + (y * x)
one = succ zero
data Roman : ℕ → ℕ → Set where
i : Roman one one
{- v : Roman one five
x : Roman ten one
... -}
madeup : ∀ {a b} (x : Roman a b) → (c : ℕ) → Roman a c
record Join (A B C : Set) : Set where
field jo : A → B → C
two : ∀ {a} → Join (Roman a one) (Roman a one) (Roman a (one + one))
two = record { jo = λ l r → madeup l (one + one) }
_#_ : ∀ {a b c d C} → {{j : Join (Roman a b) (Roman c d) C}} → Roman a b → Roman c d → C
(_#_) {{j}} = Join.jo j
-- roman = (_#_) {{two}} i i -- works
roman : Roman one (one + one)
roman = {! i # i!} -- doesn't work
Clearly, if I specify the implicit explicitly, it works - so I am confident it is not the type of the function that is wrong.
Your example works fine in development version of Agda. If you are using a version older than 2.3.2, this passage from release notes could clarify why it doesn't compile for you:
* Instance arguments resolution will now consider candidates which
still expect hidden arguments. For example:
record Eq (A : Set) : Set where
field eq : A → A → Bool
open Eq {{...}}
eqFin : {n : ℕ} → Eq (Fin n)
eqFin = record { eq = primEqFin }
testFin : Bool
testFin = eq fin1 fin2
The type-checker will now resolve the instance argument of the eq
function to eqFin {_}. This is only done for hidden arguments, not
instance arguments, so that the instance search stays non-recursive.
(source)
That is, before 2.3.2, the instance search would completly ignore your two instance because it has a hidden argument.
While instance arguments behave a bit like type classes, note that they will only commit to an instance if there's only one type correct version in scope and they will not perform a recursive search:
Instance argument resolution is not recursive. As an example,
consider the following "parametrised instance":
eq-List : {A : Set} → Eq A → Eq (List A)
eq-List {A} eq = record { equal = eq-List-A }
where
eq-List-A : List A → List A → Bool
eq-List-A [] [] = true
eq-List-A (a ∷ as) (b ∷ bs) = equal a b ∧ eq-List-A as bs
eq-List-A _ _ = false
Assume that the only Eq instances in scope are eq-List and eq-ℕ.
Then the following code does not type-check:
test = equal (1 ∷ 2 ∷ []) (3 ∷ 4 ∷ [])
However, we can make the code work by constructing a suitable
instance manually:
test′ = equal (1 ∷ 2 ∷ []) (3 ∷ 4 ∷ [])
where eq-List-ℕ = eq-List eq-ℕ
By restricting the "instance search" to be non-recursive we avoid
introducing a new, compile-time-only evaluation model to Agda.
(source)
Now, as for the second part of the question: I'm not exactly sure what your final goal is, the structure of the code ultimately depends on what you want to do once you construct the number. That being said, I wrote down a small program that allows you to enter roman numerals without going through the explicit data type (forgive me if I didn't catch your intent clearly):
A roman numeral will be a function which takes a pair of natural numbers - the value of previous numeral and the running total. If it's smaller than previous numeral, we'll subtract its value from the running total, otherwise we add it up. We return the new running total and value of current numeral.
Of course, this is far from perfect, because there's nothing to prevent us from typing I I X and we end up evaluating this as 10. I leave this as an exercise for the interested reader. :)
Imports first (note that I'm using the standard library here, if you do not want to install it, you can just copy the definition from the online repo):
open import Data.Bool
open import Data.Nat
open import Data.Product
open import Relation.Binary
open import Relation.Nullary.Decidable
This is our numeral factory:
_<?_ : Decidable _<_
m <? n = suc m ≤? n
makeNumeral : ℕ → ℕ × ℕ → ℕ × ℕ
makeNumeral n (p , c) with ⌊ n <? p ⌋
... | true = n , c ∸ n
... | false = n , c + n
And we can make a few numerals:
infix 500 I_ V_ X_
I_ = makeNumeral 1
V_ = makeNumeral 5
X_ = makeNumeral 10
Next, we have to apply this chain of functions to something and then extract the running total. This is not the greatest solution, but it looks nice in code:
⟧ : ℕ × ℕ
⟧ = 0 , 0
infix 400 ⟦_
⟦_ : ℕ × ℕ → ℕ
⟦ (_ , c) = c
And finally:
test₁ : ℕ
test₁ = ⟦ X I X ⟧
test₂ : ℕ
test₂ = ⟦ X I V ⟧
Evaluating test₁ via C-c C-n gives us 19, test₂ then 14.
Of course, you can move these invariants into the data type, add new invariants and so on.

Resources