Problem
I have a simple coinductive record with a single field of a sum type. Unit gives us a simple type to play with.
open import Data.Maybe
open import Data.Sum
data Unit : Set where
unit : Unit
record Stream : Set where
coinductive
field
step : Unit ⊎ Stream
open Stream
Works
valid passes the termination checker:
valid : Maybe Unit → Stream
step (valid x) = inj₂ (valid x)
Breaks
But say I want to eliminate the Maybe Unit member and only recurse when I have a just.
invalid₀ : Maybe Unit → Stream
step (invalid₀ x) = maybe (λ _ → inj₂ (invalid₀ x)) (inj₁ unit) x
Now the termination checker is unhappy!
Termination checking failed for the following functions:
invalid₀
Problematic calls:
invalid₀ x
Why does this not satisfy the termination checker? Is there a way around this or is my conceptual understanding incorrect?
Background
agda --version yields Agda version 2.6.0-7ae3882. I am compiling only with the default options.
The output of -v term:100 is here: https://gist.github.com/emilyhorsman/f6562489b82624a5644ed78b21366239
Attempted Solutions
Use Agda version 2.5.4.2. Does not fix.
Use --termination-depth=10. Does not fix.
You could make use of sized types here.
open import Data.Maybe
open import Data.Sum
open import Size
data Unit : Set where
unit : Unit
record Stream {i : Size} : Set where
coinductive
field
step : {j : Size< i} → Unit ⊎ Stream {j}
open Stream
valid : Maybe Unit → Stream
step (valid x) = inj₂ (valid x)
invalid₀ : {i : Size} → Maybe Unit → Stream {i}
step (invalid₀ x) = maybe (λ _ → inj₂ (invalid₀ x)) (inj₁ unit) x
_ : step (invalid₀ (nothing)) ≡ inj₁ unit
_ = refl
_ : step (invalid₀ (just unit)) ≡ inj₂ (invalid₀ (just unit))
_ = refl
Being more explicit about the Size arguments in the definition of invalid₀:
step (invalid₀ {i} x) {j} = maybe (λ _ → inj₂ (invalid₀ {j} x)) (inj₁ unit) x
where j has type Size< i, so the recursive call to invalid₀ is on a “smaller” Size.
Notice that valid, which didn't need any “help” to pass termination checking, doesn't need to reason about Size's at all.
The problem is that Agda cant see that invalid₀ is productive. This is because it is both recursive and not guarded by a constructor. Agda does not look inside the definition of maybe when deciding whether this is terminating or not.
Here is an implementation that satisfies the termination checker because both branches are guarded by constructors and/or non-recursive:
okay₀ : Maybe Unit → Stream
step (okay₀ x#(just _)) = inj₂ (invalid₀ x)
step (okay₀ nothing) = inj₁ unit
The important part is the recursive just case has the constructor inj₂ as the top level of the expression.
Related
I wrote a function on the natural numbers that uses the operator _<?_ with the with-abstraction.
open import Data.Maybe
open import Data.Nat
open import Data.Nat.Properties
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary
fun : ℕ → ℕ → Maybe ℕ
fun x y with x <? y
... | yes _ = nothing
... | no _ = just y
I would like to prove that if the result of computing with fun is nothing then the original two values (x and y) fulfill x < y.
So far all my attempts fall short to prove the property:
prop : ∀ (x y)
→ fun x y ≡ nothing
→ x < y
prop x y with fun x y
... | just _ = λ()
... | nothing = λ{refl → ?} -- from-yes (x <? y)}
-- This fails because the pattern matching is incomplete,
-- but it shouldn't. There are no other cases
prop' : ∀ (x y)
→ fun x y ≡ nothing
→ x < y
prop' x y with fun x y | x <? y
... | nothing | yes x<y = λ{refl → x<y}
... | just _ | no _ = λ()
--... | _ | _ = ?
In general, I've found that working with the with-abstraction is painful. It is probably due to the fact that with and | hide some magic in the background. I would like to understand what with and | really do, but the "Technical details" currently escape my understanding. Do you know where to look for to understand how to interpret them?
Concrete solution
You need to case-split on the same element on which you case-split in your function:
prop : ∀ x y → fun x y ≡ nothing → x < y
prop x y _ with x <? y
... | yes p = p
In the older versions of Agda, you would have had to write the following:
prop-old : ∀ x y → fun x y ≡ nothing → x < y
prop-old x y _ with x <? y
prop-old _ _ refl | yes p = p
prop-old _ _ () | no _
But now you are able to completely omit a case when it leads to a direct contradiction, which is, in this case, that nothing and just smth can never be equal.
Detailed explanation
To understand how with works you first need to understand how definitional equality is used in Agda to reduce goals. Definitional equality binds a function call with its associated expression depending on the structure of its input. In Agda, this is easily seen by the use of the equal sign in the definition of the different cases of a function (although since Agda builds a tree of cases some definitional equalities might not hold in some cases, but let's forget this for now).
Let us consider the following definition of the addition over naturals:
_+_ : ℕ → ℕ → ℕ
zero + b = b
(suc a) + b = suc (a + b)
This definition provides two definitional equalities that bind zero + b with b and (suc a) + b with suc (a + b). The good thing with definitional equalities (as opposed to propositional equalities) is that Agda automatically uses them to reduce goals whenever possible. This means that, for instance, if in a further goal you have the element zero + p for any p then Agda will automatically reduce it to p.
To allow Agda to do such reduction, which is fundamental in most cases, Agda needs to know which of these two equalities can be exploited, which means a case-split on the first argument of this addition has to be made in any further proof about addition for a reduction to be possible. (Except for composite proofs based on other proofs which use such case-splits).
When using with you basically add additional definitional equalities depending on the structure of the additional element. This only makes sense, understanding that, that you need to case-split on said element when doing proofs about such a function, in order for Agda once again to be able to make use of these definitional equalities.
Let us take your example and apply this reasoning to it, first without the recent ability to omit impossible cases. You need to prove the following statement:
prop-old : ∀ x y → fun x y ≡ nothing → x < y
Introducing parameters in the context, you write the following line:
prop-old x y p = ?
Having written that line, you need to provide a proof of x < y with the elements in the context. x and y are just natural so you expect p to hold enough information for this result to be provable. But, in this case, p is just of type fun x y ≡ nothing which does not give you enough information. However, this type contains a call to function fun so there is hope ! Looking at the definition of fun, we can see that it yields two definitional equalities, which depend on the structure of x <? y. This means that adding this parameter to the proof by using with once more will allow Agda to make use of these equalities. This leads to the following code:
prop-old : ∀ x y → fun x y ≡ nothing → x < y
prop-old x y p with x <? y
prop-old _ _ p | yes q = ?
prop-old _ _ p | no q = ?
At that point, not only did Agda case-split on x <? y, but it also reduced the goal because it is able, in both cases, to use a specific definitional equality of fun. Let us take a closer look at both cases:
In the yes q case, p is now of type nothing ≡ nothing and q is of type x < y which is exactly what you want to prove, which means the goal is simply solved by:
prop-old _ _ p | yes q = q
I the no q case, something more interesting happens, which is somewhat harder to understand. After reduction, p is now of type just y ≡ nothing because Agda could use the second definitional equality of fun. Since _≡_ is a data type, it is possible to case-split on p which basically asks Agda: "Look at this data type and give me all the possible constructors for an element of type just y ≡ nothing". At first, Agda only finds one possible constructor, refl, but this constructor only builds an element of a type where both sides of the equality are the same, which is not the case here by definition because just and nothing are two distinct constructors from the same data type, Maybe. Agda then concludes that there are no possible constructors that could ever build an element of such type, hence this case is actually not possible, which leads to Agda replacing p with the empty pattern () and dismissing this case. This line is thus simply:
prop-old _ _ () | no _
In the more recent versions of Agda, as I explained earlier, some of these steps are done directly by Agda which allows us to directly omit impossible cases when the emptiness of a pattern can be deduced behind the curtain, which leads to the prettier:
prop : ∀ x y → fun x y ≡ nothing → x < y
prop x y _ with x <? y
... | yes p = p
But it is the same process, just done a bit more automatically. Hopefully, these elements will be of some use in your journey towards understanding Agda.
I'm trying to understand Agda's built in reflection mechanisms, so I decided to write a simple function that takes a string for an identifier,
a quoted type, and a quoted term, and simply defines a term of the given type with the given string identifier. Thus, I wrote the following:
testDefineName' : String → TC Type → TC Term → TC ⊤
testDefineName' s t a =
bindTC (freshName s)
(λ n → bindTC t
(λ t' → bindTC a
(λ a' → (bindTC (declareDef (arg (arg-info visible relevant) n) t')
(λ _ → defineFun n ((clause [] a') ∷ []))))))
unquoteDecl = (testDefineName' "test" (quoteTC ℕ) (quoteTC zero))
This type-checks, but, when I try to use "test" elsewhere I get a Not in scope: test error.
The documentation for unquoteDecl is kind of opaque. Appaently declarations should be of the form
unquoteDecl x_1 x_2 ... x_n = m
where the x_i are Names, and m has type TC \top, so maybe what I was trying to do isn't actually possible, but I still don't understand how this mechanism works: if m has to be of type TC ⊤, and thus cannot be a function of the names x_1 x_2 ... x_n, I don't see how it is possible to bring any new names into scope using unquoteDecl at all!
So, to sum up:
Is it possible to define a function like mine using Agda's reflection mechanism so that I can bring new names into scope using a String argument? What I want is something like:
<boilerplate code for unquoting> testDefineName' "test" (quoteTC ℕ) (quoteTC zero)
test' : ℕ
test' = test
to compile (i.e. I can actually use the new name, "test")
and if not, by what mechanism can m make use of the names x_1 ... x_n? Can m actually have a type like List Name → TC ⊤, contrary to the documentation?
Based on the way Ulf uses unquoteDecl, I have the impression that you need to list on the LHS the names which are going to extend the scope.
The problem with your setup is that you don't know the Name as you generate a fresh one from a String and have no way of getting hold of it AFAIK. I have the impression that freshName is only supposed to be used to generate internal names from inside a tactic.
If you make testDefineName' take a Name rather than a String then everything works out:
testDefineName' : Name → TC Type → TC Term → TC ⊤
testDefineName' n t a = bindTC t
$ λ t' → bindTC a
$ λ a' → bindTC (declareDef (arg (arg-info visible relevant) n) t')
$ λ _ → defineFun n ((clause [] a') ∷ [])
unquoteDecl test = testDefineName' test (quoteTC ℕ) (quoteTC zero)
Reading this answer prompted me to try to construct, and then prove, the canonical form of polymorphic container functions. The construction was straightforward, but the proof stumps me. Below is a simplified-minimized version of how I tried to write the proof.
The simplified version is proving that sufficiently polymorphic functions, due to parametricity, can't change their behaviour only based on the choice of parameter. Let's say we have functions of two arguments, one of a fixed type and one parametric:
PolyFun : Set → Set _
PolyFun A = ∀ {X : Set} → A → X → A
the property I'd like to prove:
open import Relation.Binary.PropositionalEquality
parametricity : ∀ {A X Y} → (f : PolyFun A) → ∀ a x y → f {X} a x ≡ f {Y} a y
parametricity f a x y = {!!}
Are statements like that provable from inside Agda?
Nope, there's no parametricity principle accessible in Agda (yet! [1]).
However you can use these combinators to build the type of the corresponding free theorem and postulate it:
http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Libraries.LightweightFreeTheorems
[1] http://www.cse.chalmers.se/~mouling/share/PresheafModelParametericTT.pdf
I want to prove
∀ {ℓ} {A B C D : Set ℓ} → (A → B) ≡ (C → D) → A ≡ C
(and similar for the codomain).
If I had a function domain that returns the domain of a function type, I could write the proof as
cong domain
but I don't think it's possible to write such a function.
Is there any way to do this?
I posed a very similar question on the Agda mailing list a few months ago, see: http://permalink.gmane.org/gmane.comp.lang.agda/5624. The short answer is that you cannot prove this in Agda.
The technical reason is that the unification algorithm used internally by Agda for pattern matching doesn't include a case for problems of the form (A → B) ≡ (C → D), so this definition does not typecheck:
cong-domain : ∀ {ℓ} {A B C D : Set ℓ} → (A → B) ≡ (C → D) → A ≡ C
cong-domain refl = refl
It is also impossible to define the function domain directly. Think about it: what should be the domain of a type that is not a function type, e.g. Bool?
The deeper reason why you cannot prove this is that it would be incompatible with the univalence axiom from Homotopy Type Theory. In an answer given by Guillaume Brunerie on my mail, he gives the following example: Consider the two types Bool -> Bool and Unit -> (Bool + Bool). Both have 4 elements, so we can use the univalence axiom to give a proof of type Bool -> Bool ≡ Unit -> (Bool + Bool) (in fact there are 24 different proofs). But clearly we do not want Bool ≡ Unit! So in the presence of univalence, we cannot assume that equal function types have equal domains.
In the end, I 'solved' this problem by passing an extra argument of type A ≡ C everywhere it was needed. I know it's not ideal, but maybe you can do the same.
I should also note that Agda does include an option for injective type constructors, which you can enable by putting {-# OPTIONS --injective-type-constructors #-} at the top of your .agda file. This allows you for example to prove A ≡ B from List A ≡ List B, but unfortunately this only works for type constructors such as List, and not for function types.
You could of course always make a feature request at https://code.google.com/p/agda/issues/list to add a option --injective-function-types to Agda. This option would be incompatible with univalence, but so is --injective-type-constructors, yet for many applications this is not a real problem. I feel that the main Agda developers are usually very open to such requests, and very fast to add them to the development version of Agda.
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.