When I write a lot of agda code I always end up having this cumbersome pattern in my code. Suppose I have this record type defining a mathematical structure:
record A (T : Set) : Set where
m1 = -- ...
m2 = -- ...
m3 = -- ...
field
f1 : -- ...
f2 : -- ...
f3 : -- ...
then I prove a property of this structure A:
theorem : ∀ {S} -> A S -> -- ...
theorem a = -- ...
where
m1 = A.m1 a
m2 = A.m2 a
f1 = A.f1 a
f2 = A.f2 a
-- ...
This is very annoying. I could open A but then I just have m1, m2 that maps a to the object I want. I want something like open a so that m1 refers directly to (A.m1 a). I couldn't find anything on this matter in Agda documentation. Is there such syntactic sugar? This problem is responsible of great majority (maybe >60% of my code). In every single theorem I open up the whole structure... What am I doing wrong? How can I fix this?
Related
I would like to define a head function for lists.
In order to avoid trying to compute the head of an empty list one
can either work with vectors of length greater than one (i.e., Vec (suc n))
or work with Lists, but pass a proof that the list is non-empty to head.
(This is what "Dependent Types at Work" calls internal vs external
programming logic, I believe.)
I am interested in the latter approach.
Note that there is a SO answer which addresses this, but I wanted
a minimal approach. (For example, I would prefer not to use Instance Arguments
unless they are required.)
Below is my attempt, but I don't fully understand what is going on.
For example:
It's not clear why I was able to skip the head [] case. Obviously it's related to the "proof" I pass in but I would have expected I would need some kind of case with () in it.
When I type check (C-c C-l) I seem to get two goals as output.
I would have liked to have seen tmp2 fail to type check.
Any insight would be very welcome.
In particular, what is the "right" way(s) to do what I am trying to do?
data List (A : Set) : Set where
[] : List A
_::_ : A → List A → List A
{-
head1 : {A : Set} → (as : List A) → A
-- As expected, complains about missing case `head1 []`.
head1 (a :: aa) = a
-}
data ⊤ : Set where
tt : ⊤
data ⊥ : Set where
isNonEmpty : {A : Set} → List A → Set
isNonEmpty [] = ⊥
isNonEmpty (_ :: _) = ⊤
head : {A : Set} → (as : List A) → {isNonEmpty as} → A
head (a :: _) = a
-- Define just enough to do some examples
data Nat : Set where
zero : Nat
suc : Nat → Nat
{-# BUILTIN NATURAL Nat #-}
len1 : List Nat
len1 = 17 :: []
tmp : Nat
tmp = head len1
tmp1 : Nat
tmp1 = head len1 { tt }
len0 : List Nat
len0 = []
tmp2 : Nat
tmp2 = head len0
The user manual on coverage checking in Agda explains that in certain situations absurd clauses can be left out completely:
In many common cases, absurd clauses may be omitted as long as the remaining clauses reveal sufficient information to indicate what arguments to case split on. [...] Absurd clauses may be omitted if removing the corresponding internal nodes from the case tree does not result in other internal nodes becoming childless.
Note that you can still write the absurd clause manually if you want and Agda will accept it.
What you are getting are not two unsolved holes but two unsolved metavariables. These metavariables were created by Agda to fill in the implicit argument to head in the definitions of tmp and tmp2 respectively, and Agda's constraint solver wasn't able to solve them. For the metavariable in tmp, this is because you defined ⊤ as a datatype instead of a record type, and Agda only applies eta-equality for record types. For the metavariable in tmp2, the type is ⊥ so there is no hope that Agda would be able to find a solution here.
When using Agda, you should see unsolved metavariables as a specific case of "failing to typecheck". They are not a hard type error because that would prevent you from continuing to use the interactive editing of Agda, and in many cases further filling in holes will actually solve the metavariables. However, they indicate "this program is not finished" just as much as an actual type error would.
I'm working in Cubical agda and trying to build up some common utilities for later proofs. One of these is that for any type A it is the 'same' as the type Σ A (\_ -> Top) where Top is the type with one element. And the issue is how to best expose this 'sameness' from the utility library. I can expose it as an equivalence, a path or an isomorphism, and maybe multiple ones.
I originally exposed it as just a path: top-path : Path A (Σ A (\_ -> Top)) which is built up using glue types from an underlying top-equiv : A ≃ Σ A (\_ -> Top). But when trying to use this in later proofs I found out that transporting along this path did not compute as I expected. My expectation was that it composed with fst to the identity, but in practice I found that it sometimes left in transp and prim^unglue terms. This was not the case if I used a particular concrete type for A, or if I used a similar construction using the equivalence.
Example:
-- Working
compute-top-path-Bool : (a : Bool) -> fst (transport (top-path Bool) a) == a
compute-top-path-Bool a = refl
compute-top-equiv-Any : (a : Bool) -> fst (transport-equiv (top-equiv Bool) a) == a
compute-top-equiv-Any a = refl
-- Broken
compute-top-path-Any : (a : A) -> fst (transport (top-path A) a) == a
compute-top-path-Any a = refl
--
-- Checking test (/Users/endobson/tmp/agda/test.agda).
-- /Users/endobson/tmp/agda/test.agda:104,26-30
-- transp (λ i → A) i0 (fst (prim^unglue a)) != a of type A
-- when checking that the expression refl has type
-- fst (transport (top-path A) a) == a
--
Self contained reproduction: https://gist.github.com/endobson/62605cfc15a92b9111391b459d03b548, and I'm using Agda version 2.6.1.3.
Thus my question is what is best solution for this problem? Am I somehow constructing my paths in a too complicated way and if I made them in a different way then the computational behavior would be better? Or is exposing the equivalence directly from my utility library expected? I find exposing the equivalence 'inelegant' as it seems that paths should be able to do this, but am not against doing so if they are known to be the better tool for this particular use case.
In the agda/cubical library we do tend to export the equivalence (or the iso) along with the path, because of issues like the one you mention.
The reason for those extra transp calls is that transport for Glue has to work in the general case where they might actually be required.
fst (prim^unglue a) should reduce away if you ask for the normal form though.
I've been playing around with the idea of writing programs that run on Streams and properties with them, but I feel that I am stuck even with the simplest of things. When I look at the definition of repeat in Codata/Streams in the standard library, I find a construction that I haven't seen anywhere in Agda: λ where .force →.
Here, an excerpt of a Stream defined with this weird feature:
repeat : ∀ {i} → A → Stream A i
repeat a = a ∷ λ where .force → repeat a
Why does where appear in the middle of the lambda function definition?, and what is the purpose of .force if it is never used?
I might be asking something that is in the documentation, but I can't figure out how to search for it.
Also, is there a place where I can find documentation to use "Codata" and proofs with it? Thanks!
Why does where appear in the middle of the lambda function definition?,
Quoting the docs:
Anonymous pattern matching functions can be defined using one of the
two following syntaxes:
\ { p11 .. p1n -> e1 ; … ; pm1 .. pmn -> em }
\ where p11 .. p1n -> e1 … pm1 .. pmn -> em
So λ where is an anonymous pattern matching function. force is the field of Thunk and .force is a copattern in postfix notation (originally I said nonsense here, but thanks to #Cactus it's now fixed, see his answer).
Also, is there a place where I can find documentation to use "Codata" and proofs with it? Thanks!
Check out these papers
Normalization by Evaluation in the Delay Monad
A Case Study for Coinduction via Copatterns and Sized Types
Equational Reasoning about Formal Languages in Coalgebraic Style
Guarded Recursion in Agda via Sized Types
As one can see in the definition of Thunk, force is the field of the Thunk record type:
record Thunk {ℓ} (F : Size → Set ℓ) (i : Size) : Set ℓ where
coinductive
field force : {j : Size< i} → F j
So in the pattern-matching lambda, .force is not a dot pattern (why would it be? there is nothing prescribing the value of the parameter), but instead is simply syntax for the record field selector force. So the above code is equivalent to making a record with a single field called force with the given value, using copatterns:
repeat a = a :: as
where
force as = repeat a
or, which is actually where the .force syntax comes from, using postfix projection syntax:
repeat a = a :: as
where
as .force = repeat a
I wanted to implement this statement in agda ;
A dedekind cut is a pair (L, U) of mere predicates L : Q -> Set and R : Q -> Set which is
1) inhibited : exists (q : Q) . L(q) ^ exists (r : Q) . U(r)
I have tried in this way,
record cut : Set where
field
L : Q -> Set
R : Q -> Set
inhibited : exists (q : Q) . L(q) ^ exists (r : Q) . U(r)
but this is not working. I want to write this and i am struck please help. And also what is the difference between 1)data R : Set and record R : Set and 2) data R : Set and data R : Q -> Set
I don't know about defining the whole of the dedekind cut, though I did find your definition on page 369 of Homotopy Type Theory: Univalent Foundations of Mathematics.
Here is the syntax for defining what you asked about in your question in two forms, one using the standard library and one expanded out to show what it is doing.
open import Data.Product using (∃)
record Cut (Q : Set) : Set₁ where
field
L U : Q → Set -- The two predicates
L-inhabited : ∃ L
U-inhabited : ∃ U
If we manually expand the definition of ∃ (exists) we have:
record Cut′ (Q : Set) : Set₁ where
field
L U : Q → Set -- The two predicates
q r : Q -- Witnesses
Lq : L q -- Witness satisfies predicate
Ur : U r -- Witness satisfies predicate
Note that the record has type Set₁ due to the types of fields L and U.
Regarding your question about records and inductively defined data types, there are lots of differences. You might want to start with the wiki and ask more specific questions if you get stuck somewhere: Data, Records
Here's what I understand about Relation.Binary.PropositionalEquality.TrustMe.trustMe: it seems to take an arbitrary x and y, and:
if x and y are genuinely equal, it becomes refl
if they are not, it behaves like postulate lie : x ≡ y.
Now, in the latter case it can easily make Agda inconsistent, but this in itself is not so much a problem: it just means that any proof using trustMe is a proof by appeal to authority. Moreover, though you can use such things to write coerce : {A B : Set} -> A -> B, it turns out to be the case that coerce {ℕ} {Bool} 0 doesn't reduce (at least, not according to C-c C-n), so it's really not analogous to, say, Haskell's semantic-stomping unsafeCoerce.
So what do I have to fear from trustMe? On the other hand, is there ever a reason to use it outside of implementing primitives?
Indeed, attempting to pattern match on trustMe which does not evaluate to refl results in a stuck term. Perhaps it is enlightening to see (part of) the code that defines the primitive operation behind trustMe, primTrustMe:
(u', v') <- normalise (u, v)
if (u' == v') then redReturn (refl $ unArg u) else
return (NoReduction $ map notReduced [a, t, u, v])
Here, u and v represent the terms x and y, respectively. The rest of the code can be found in the module Agda.TypeChecking.Primitive.
So yes, if x and y are not definitionally equal, then primTrustMe (and by extension trustMe) behaves as a postulate in the sense that evaluation simply gets stuck. However, there's one crucial difference when compiling Agda down to Haskell. Taking a look at the module Agda.Compiler.MAlonzo.Primitives, we find this code:
("primTrustMe" , Right <$> do
refl <- primRefl
flip runReaderT 0 $
term $ lam "a" (lam "A" (lam "x" (lam "y" refl))))
This looks suspicious: it always returns refl no matter what x and y are. Let's have a test module:
module DontTrustMe where
open import Data.Nat
open import Data.String
open import Function
open import IO
open import Relation.Binary.PropositionalEquality
open import Relation.Binary.PropositionalEquality.TrustMe
postulate
trustMe′ : ∀ {a} {A : Set a} {x y : A} → x ≡ y
transport : ℕ → String
transport = subst id (trustMe {x = ℕ} {y = String})
main = run ∘ putStrLn $ transport 42
Using trustMe inside transport, compiling the module (C-c C-x C-c) and running the resulting executable, we get... you guessed it right - a segfault.
If we instead use the postulate, we end up with:
DontTrustMe.exe: MAlonzo Runtime Error:
postulate evaluated: DontTrustMe.trustMe′
If you do not intend to compile your programs (at least using MAlonzo) then inconsistency should be your only worry (on the other hand, if you only typecheck your programs then inconsistency usually is kind of a big deal).
There are two use cases I can think of at the moment, first is (as you've said) for implementing primitives. The standard library uses trustMe in three places: in implementation of decidable equality for Names (Reflection module), Strings (Data.String module) and Chars (Data.Char module).
The second one is much like the first one, except that you provide the data type and the equality function yourself and then use trustMe to skip the proving and just use the equality function to define a decidable equality. Something like:
open import Data.Bool
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary
data X : Set where
a b : X
eq : X → X → Bool
eq a a = true
eq b b = true
eq _ _ = false
dec-eq : Decidable {A = X} _≡_
dec-eq x y with eq x y
... | true = yes trustMe
... | false = no whatever
where postulate whatever : _
However, if you screw up eq, the compiler cannot save you.