Usage of Agda Data.Bool solver - agda

I've tried to use Agda Data.Bool solver in Agda version 2.6.1-4e989c1
module example where
open import Data.Bool hiding ( _∨_ )
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Data.Bool.Solver using (module xor-∧-Solver)
open xor-∧-Solver
problem0' : ( Cat : Bool ) → (Cat xor Cat ) ≡ false
problem0' = solve 1 (λ c → (c :+ c ) := con false ) refl
so far so good.
problem1' : ( Cat : Bool ) → (Cat ∧ (Cat xor true )) ≡ false
problem1' = solve 1 (λ c → ((c :* (c :+ con true )) ) := con false ) ?
Putting refl in the ?, give us a very long conflict including Data.Vec.Vec.[])
!=< false of type Bool. Am I miss something?

If you ask for the normalized goal (most commands relating to goal printing can be prefixed by C-u C-u to show the normal form of the output) you will get:
{x : Bool} → (x xor true) ∧ x xor false ≡ false
which is how far the solver was able to "simplify" the problem.
I could be wrong, but this equality doesn't seem to follow from just the laws of commutative rings, which is what the solver works with.
A solver specific to Bool could take advantage of the extra structure, or even just case split if there aren't too many variables.

Related

Decidable equality of data types in Agda

I am trying to prove decidable equality of a data type in Agda using the Agda stdlib. I have the following code, but I am unsure what to fill in the hole. The goal seems to make sense, but actually constructing it is challenging.
Is this possible in Agda and are there any ideas on how to solve this?
open import Data.String as String hiding (_≟_)
open import Relation.Nullary
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
module Problem1 where
data Test : Set where
test : String → Test
infix 4 _≟_
_≟_ : Decidable {A = Test} _≡_
test x ≟ test x₁ with x String.≟ x₁
... | yes refl = yes refl
... | no ¬a = no {!!}
The hole:
Goal: ¬ test x ≡ test x₁
————————————————————————————————————————————————————————————
¬a : ¬ x ≡ x₁
x₁ : ℕ
x : ℕ
This is actually a one liner, relying on case splitting over the equality proof inside an anonymous function, as follows:
... | no ¬a = no λ {refl → ¬a refl}

With-abstraction and equality

In the following example
open import Agda.Builtin.Nat
open import Agda.Builtin.Equality
postulate
f : Nat → Nat
g : ∀{x y} → f x ≡ suc y → Nat
h : Nat → Nat
h x with f x
h x | zero = zero
h x | suc y = g {x} {y} {!refl!}
Agda doesn't accept refl for an argument.
The main questions are,
what am I doing wrong?
what is the correct/optimal/established/preferred way of proving stuff like this?
And of course any insights into Agda's behavior are greatly appreciated.
≡-Reasoning and 'with' patterns and Agda: type isn't simplified in with block should answer your questions. The official docs describe how to do what you want, but they don't seem to be too beginner-friendly.

Is there any non-trivial code that uses Data.Maybe.Is-just?

The Agda standard library provides a data type Maybe accompanied with a view Any.
Then there is the property Is-just defined using Any. I found working with this type difficult as the standard library provides exactly no tooling for Any.
Thus I am looking for examples on how to work with Is-just effectively. Is there an open source project that uses it?
Alternatively, I am seeking how to put it to good use:
Given Is-just m and Is-nothing m, how to eliminate? Can Relation.Nullary.Negation.contradiction be used here?
Given a property p : ... → (mp : Is-just m) → ... → ... ≡ to-witness mp that needs to be shown inductively by p ... = {! p ... (subst Is-just m≡somethingelse mp) ... !}, the given term does not fill the hole, because it has type ... ≡ to-witness (subst Is-just m≡somethingelse mp).
Often it seems easier to work with Σ A (_≡_ m ∘ just) than Is-just m.
Regarding your first question, it is possible to derive a contradiction from having both Is-just m and Is-nothing m in context. You can then use ⊥-elim to prove anything.
module isJust where
open import Level
open import Data.Empty
open import Data.Maybe
contradiction :
{ℓ : Level} {A : Set ℓ} {m : Maybe A}
(j : Is-just m) (n : Is-nothing m) → ⊥
contradiction (just _) (just pr) = pr
The second one is a bit too abstract for me to be sure whether what I'm suggesting will work but the usual strategies are to try to pattern match on the value of type Maybe A or on the proof that Is-just m.
As for using another definition of Is-just, I tend to like
open import Data.Bool
isJust : {ℓ : Level} {A : Set ℓ} (m : Maybe A) → Set
isJust m = T (is-just m)
because it computes.

Using multiple EqReasoning instantiations conveniently

Is there a way to conveniently use multiple instantiations of EqReasoning where the underlying Setoid is not necessarily semantic equality (i.e. ≡-Reasoning cannot be used)? The reason that ≡-Reasoning is convenient is that the type argument is implicit and it uniquely determines the Setoid in use by automatically selecting semantic equality. When using arbitrary Setoids there is no such unique selection. However a number of structures provide a canonical way to lift a Setoid:
Data.Maybe and Data.Covec have a setoid member.
Data.Vec.Equality.Equality provides enough definitions to write a canonical Setoid lifting for Vec as well. Interestingly there is also is a slightly different equality available at Relation.Binary.Vec.Pointwise, but it does not provide a direct lifting either albeit implementing all the necessary bits.
Data.List ships a Setoid lifting in Relation.Binary.List.Pointwise.
Data.Container also knows how to lift a Setoid.
By using any of these structures, one automatically gets to work with multiple Setoids even if one started out with one. When proofs use these structures (multiple of them in a single proof), it becomes difficult to write down the proof, because EqReasoning must be instantiated for all of them even though each particular Setoid is kind of obvious. This can be done by renaming begin_, _≈⟨_⟩_ and _∎, but I don't consider this renaming convenient.
Consider for example, a proof in the Setoid of Maybe where a sequence of arguments needs to be wrapped in Data.Maybe.Eq.just (think cong just) or a proof in an arbitrary Setoid that temporarily needs to wrap things in a just constructor exploiting its injectivity.
Normally, the only way Agda can pick something for you is when it is uniquely determined by the context. In the case of EqReasoning, there isn't usually enough information to pin down the Setoid, even worse actually: you could have two different Setoids over the same Carrier and _≈_ (consider for example two definitionally unequal proofs of transitivity in the isEquivalence field).
However, Agda does allow special form of implicit arguments, which can be filled as long as there is only one value of the desired type. These are known as instance arguments (think instance as in Haskell type class instances).
To demonstrate roughly how this works:
postulate
A : Set
a : A
Now, instance arguments are wrapped in double curly braces {{}}:
elem : {{x : A}} → A
elem {{x}} = x
If we decide to later use elem somewhere, Agda will check for any values of type A in scope and if there's only one of them, it'll fill that one in for {{x : A}}. If we added:
postulate
b : A
Agda will now complain that:
Resolve instance argument _x_7 : A. Candidates: [a : A, b : A]
Because Agda already allows you to perform computations on type level, instance arguments are deliberately limited in what they can do, namely Agda won't perform recursive search to fill them in. Consider for example:
eq : ... → IsEquivalence _≈_ → IsEquivalence (Eq _≈_)
where Eq is Data.Maybe.Eq mentioned in your question. When you then require Agda to fill in an instance argument of a type IsEquivalence (Eq _≈_), it won't try to find something of type IsEquivalence _≈_ and apply eq to it.
With that out of the way, let's take a look at what could work. However, bear in mind that all this stands on unification and as such you might need to push it in the right direction here and there (and if the types you are dealing with become complex, unification might require you to give it so many directions that it won't be worth it in the end).
Personally, I find instance arguments a bit fragile and I usually avoid them (and from a quick check, it would seem that so does the standard library), but your experience might vary.
Anyways, here we go. I constructed a (totally nonsensical) example to demonstrate how to do it. Some boilerplate first:
open import Data.Maybe
open import Data.Nat
open import Relation.Binary
import Relation.Binary.EqReasoning as EqR
To make this example self-contained, I wrote some kind of Setoid with natural numbers as its carrier:
data _≡ℕ_ : ℕ → ℕ → Set where
z≡z : 0 ≡ℕ 0
s≡s : ∀ {m n} → m ≡ℕ n → suc m ≡ℕ suc n
ℕ-setoid : Setoid _ _
ℕ-setoid = record
{ _≈_ = _≡ℕ_
; isEquivalence = record
{ refl = refl
; sym = sym
; trans = trans
}
}
where
refl : Reflexive _≡ℕ_
refl {zero} = z≡z
refl {suc _} = s≡s refl
sym : Symmetric _≡ℕ_
sym z≡z = z≡z
sym (s≡s p) = s≡s (sym p)
trans : Transitive _≡ℕ_
trans z≡z q = q
trans (s≡s p) (s≡s q) = s≡s (trans p q)
Now, the EqReasoning module is parametrized over a Setoid, so usually you do something like this:
open EqR ℕ-setoid
However, we'd like to have the Setoid parameter to be implicit (instance) rather than explicit, so we define and open a dummy module:
open module Dummy {c ℓ} {{s : Setoid c ℓ}} = EqR s
And we can write this simple proof:
idʳ : ∀ n → n ≡ℕ (n + 0)
idʳ 0 = z≡z
idʳ (suc n) = begin
suc n ≈⟨ s≡s (idʳ n) ⟩
suc (n + 0) ∎
Notice that we never had to specify ℕ-setoid, the instance argument picked it up because it was the only type-correct value.
Now, let's spice it up a bit. We'll add Data.Maybe.setoid into the mix. Again, because instance arguments do not perform a recursive search, we'll have to define the setoid ourselves:
Maybeℕ-setoid = setoid ℕ-setoid
_≡M_ = Setoid._≈_ Maybeℕ-setoid
I'm going to postulate few stupid things just to demonstrate that Agda indeed picks correct setoids:
postulate
comm : ∀ m n → (m + n) ≡ℕ (n + m)
eq0 : ∀ n → n ≡ℕ 0
eq∅ : just 0 ≡M nothing
lem : ∀ n → just (n + 0) ≡M nothing
lem n = begin
just (n + 0) ≈⟨ just
(begin
n + 0 ≈⟨ comm n 0 ⟩
n ≈⟨ eq0 n ⟩
0 ∎
)⟩
just 0 ≈⟨ eq∅ ⟩
nothing ∎
I figured an alternative to the proposed solution using instance arguments that slightly bends the requirements, but fits my purpose. The major burden in the question was having to explicitly open EqReasoning multiple times and especially having to invent new names for the contained symbols. A slight improvement would be to pass the correct Setoid once per relation proof. In other words passing it to begin_ or _∎ somehow. Then we could make the Setoid implicit for all the other functions!
import Relation.Binary.EqReasoning as EqR
import Relation.Binary using (Setoid)
module ExplicitEqR where
infix 1 begin⟨_⟩_
infixr 2 _≈⟨_⟩_ _≡⟨_⟩_
infix 2 _∎
begin⟨_⟩_ : ∀ {c l} (X : Setoid c l) → {x y : Setoid.Carrier X} → EqR._IsRelatedTo_ X x y → Setoid._≈_ X x y
begin⟨_⟩_ X p = EqR.begin_ X p
_∎ : ∀ {c l} {X : Setoid c l} → (x : Setoid.Carrier X) → EqR._IsRelatedTo_ X x x
_∎ {X = X} = EqR._∎ X
_≈⟨_⟩_ : ∀ {c l} {X : Setoid c l} → (x : Setoid.Carrier X) → {y z : Setoid.Carrier X} → Setoid._≈_ X x y → EqR._IsRelatedTo_ X y z → EqR._IsRelatedTo_ X x z
_≈⟨_⟩_ {X = X} = EqR._≈⟨_⟩_ X
_≡⟨_⟩_ : ∀ {c l} {X : Setoid c l} → (x : Setoid.Carrier X) → {y z : Setoid.Carrier X} → x ≡ y → EqR._IsRelatedTo_ X y z → EqR._IsRelatedTo_ X x z
_≡⟨_⟩_ {X = X} = EqR._≡⟨_⟩_ X
Reusing the nice example from Vitus answer, we can write it:
lem : ∀ n → just (n + 0) ≡M nothing
lem n = begin⟨ Data.Maybe.setoid ℕ-setoid ⟩
just (n + 0) ≈⟨ just
(begin⟨ ℕ-setoid ⟩
n + 0 ≈⟨ comm n 0 ⟩
n ≈⟨ eq0 n ⟩
0 ∎
)⟩
just 0 ≈⟨ eq∅ ⟩
nothing ∎
where open ExplicitEqR
One still has to mention the Setoids in use, to avoid the use of instance arguments as presented by Vitus. However the technique makes it significantly more convenient.

How dangerous is trustMe?

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.

Resources