Consider the following code:
module UnresolvedMeta where
record Test (M : Set) : Set1 where
field
_≈_ : M -> M -> Set
_⊕_ : M -> M -> M
assoc⊕ : ∀ {r s t} -> ((r ⊕ s) ⊕ t) ≈ (r ⊕ (s ⊕ t))
data ℕ : Set where
n0 : ℕ
suc : ℕ -> ℕ
data _==_ : ℕ -> ℕ -> Set where
refl== : ∀ {k} -> k == k
_+_ : ℕ -> ℕ -> ℕ
k + n0 = k
k + suc m = suc (k + m)
lem-suc== : ∀ {k m} -> k == m -> suc k == suc m
lem-suc== refl== = refl==
assoc+ : ∀ {i j k} -> ((i + j) + k) == (i + (j + k))
assoc+ {i} {j} {n0} = refl== {i + j}
assoc+ {i} {j} {suc k} = lem-suc== (assoc+ {i} {j} {k})
thm-ℕ-is-a-test : Test ℕ
thm-ℕ-is-a-test = record {
_⊕_ = _+_;
_≈_ = _==_;
assoc⊕ = assoc+
}
When loaded with Agda (version 2.3.2.2), Agda prints an error "Unsolved metas at the following locations" pertaining to the line penultimate line:
assoc⊕ = assoc+
and specifically pointing to assoc+.
How do I provide a hint or otherwise change the code so it compiles without this warning?
I can of course get rid of it by unhiding the arguments, but that means I would have to specify explicit arguments everywhere, even in places where it is not needed...
You can exploit the fact that Agda allows you to specify implicit arguments even inside a lambda abstraction. More specifically, you can write this:
λ {r s t} → assoc+ {r} {s} {t}
-- with a type {r s t : ℕ} → ((r + s) + t) == (r + (s + t))
And indeed, replacing assoc+ with the expression above makes the compiler happy. It would seem that the unification has a problem with the last argument (t), so we can even ignore r and s and only fill in t explicitly:
assoc⊕ = λ {_ _ t} → assoc+ {k = t}
Related
I am trying to improve my Idris skill by looking at some of the exercises Software Foundations (originally for Coq, but I am hoping the translation to Idris not too bad). I am having trouble with the "Exercise: 1 star (plus_id_exercise)" which reads:
Remove "Admitted." and fill in the proof.
Theorem plus_id_exercise : ∀ n m o : nat,
n = m → m = o → n + m = m + o.
Proof.
(* FILL IN HERE *) Admitted.
I have translated to the following problem in Idris:
plusIdExercise : (n : Nat) ->
(m : Nat) ->
(o : Nat) ->
(n == m) = True ->
(m == o) = True ->
(n + m == m + o) = True
I am trying to perform a case by case analysis and I am having a lot of issues. The first case:
plusIdExercise Z Z Z n_eq_m n_eq_o = Refl
seems to work, but then I want to say for instance:
plusIdExercise (S n) Z Z n_eq_m n_eq_o = absurd
But this doesn't work and gives:
When checking right hand side of plusIdExercise with expected type
S n + 0 == 0 + 0 = True
Type mismatch between
t -> a (Type of absurd)
and
False = True (Expected type)
Specifically:
Type mismatch between
\uv => t -> uv
and
(=) FalseUnification failure
I am trying to say this case can never happen because n == m, but Z (= m) is never the successor of any number (n). Is there anything I can do to fix this? Am I approaching this correctly? I am somewhat confused.
I would argue that the translation is not entirely correct. The lemma stated in Coq does not use boolean equality on natural numbers, it uses the so-called propositional equality. In Coq you can ask the system to give you more information about things:
Coq < About "=".
eq : forall A : Type, A -> A -> Prop
The above means = (it is syntactic sugar for eq type) takes two arguments of some type A and produces a proposition, not a boolean value.
That means that a direct translation would be the following snippet
plusIdExercise : (n = m) -> (m = o) -> (n + m = m + o)
plusIdExercise Refl Refl = Refl
And when you pattern-match on values of the equality type, Idris essentially rewrites terms according to the corresponding equation (it's roughly equivalent to Coq's rewrite tactic).
By the way, you might find the Software Foundations in Idris project useful.
I am trying to define the sum of 1..n ∈ ℕ as n * (n + 1) / 2 in Agda
and need a proof that n*(n + 1) is even for that.
The proof is pretty simple, but there seems to be a concept I don't understand, as I am new to Agda (though neither to maths nor haskell) and learned it from http://www.cse.chalmers.se/~ulfn/papers/afp08/tutorial.pdf
(pointers to more advanced tutorials more than welcome!).
open import Data.Nat
open import Relation.Binary.PropositionalEquality
open import Data.Sum
-- A natural number is even, if there is a k ∈ ℕ with k * 2 = n.
data IsEven : ℕ → Set where
even : (k : ℕ) → IsEven (k * 2)
-- A product is even, if one of the factors is even.
even-product : {n m : ℕ} → IsEven n ⊎ IsEven m → IsEven (m * n)
even-product {n} {m} (inj₁ (even k)) = even (m * k)
even-product {n} {m} (inj₂ (even k)) = even (n * k)
The code returns
m != 2 of type ℕ
when checking that the expression even (k * m) has type
IsEven (k * 2 * m)
I already tried using with patterns to convince the compiler that k * 2 is in fact n, but to no avail. Switching m * k to k * m gives
k * m != m of type ℕ
when checking that the expression even (k * m) has type
IsEven (m * (k * 2))
You can find out what the problem is by putting {! !} markers around your attempted solution and using the C-c C-. shortcut.
even-product : {n m : ℕ} → IsEven n ⊎ IsEven m → IsEven (m * n)
even-product {n} {m} (inj₁ (even k)) = {!even (m * k)!}
even-product {n} {m} (inj₂ (even k)) = {!even (n * k)!}
Reloading the file and then pressing C-c C-. with your cursor in the first hole gives the following response:
Goal: IsEven (m * (k * 2))
Have: IsEven (m * k * 2)
————————————————————————————————————————————————————————————
n : ℕ
m : ℕ
k : ℕ
Now the problem is clear: the goal is to prove that (m * (k * 2)) is even, but you have a proof that (m * k * 2) is even.
To fix this problem, you have to use the fact that * is associative. I'll postulate it here by means of example, but obviously you'd want to give it an actual proof later.
postulate
*-assoc : (k l m : ℕ) → k * (l * m) ≡ (k * l) * m
Now we can use the rewrite keyword with *-assoc to fix the first case:
even-product : {n m : ℕ} → IsEven n ⊎ IsEven m → IsEven (m * n)
even-product {n} {m} (inj₁ (even k)) rewrite *-assoc m k 2 = even (m * k)
even-product {n} {m} (inj₂ (even k)) = {!even (n * k)!}
In the second case, C-c C-. gives the following response:
Goal: IsEven (k * 2 * n)
Have: IsEven (n * k * 2)
————————————————————————————————————————————————————————————
m : ℕ
n : ℕ
k : ℕ
So now you need to use commutativity of * as well as associativity. I'll leave the full solution as an exercise to the reader.
Isn't it easier to prove that the 2 * sum(1..n) = n * (n+1)? Which shows that n*(n+1) is even?
I've defined an operator, +- (ignore the terrible name), as follows:
infixr 10 +-
(+-) : Fin (S n) -> Fin (S m) -> Fin (S (n + m))
(+-) {n} {m} FZ f' = rewrite plusCommutative n m in weakenN n f'
(+-) {n = S n} (FS f) f' = FS (f +- f')
The intention is that it behaves exactly like + as defined on Fin, but the upper bound of the result is tighter by 1. As far as I can tell, it works correctly.
The problem I'm having is in trying to prove that (FZ +- f) = f for any f : Fin n. I'm not expecting this to be true in general, because it will usually be the case that FZ +- f has a looser bound than f on account of the call to weakenN. However, in the particular case where the FZ has type Fin 1, then the types (and the values) ought to match up.
Is there any way of indicating to Idris that I only want to assert the equality in that particular case, rather than for all possible types of FZ? Or is there a completely different approach that I ought to be taking?
If we reshuffle the definition for (+-) a bit, the proof becomes easy:
import Data.Fin
infixr 10 +-
total
(+-) : Fin (S n) -> Fin (S m) -> Fin (S (n + m))
(+-) {n = Z} {m = m} a b = b
(+-) {n = (S n)}{m = m} FZ b = rewrite plusCommutative (S n) m in weakenN (S n) b
(+-) {n = (S n)}{m = m} (FS a) b = FS (a +- b)
lem : (f : Fin (S n)) -> the (Fin 1) FZ +- f = f
lem FZ = Refl
lem (FS x) = Refl
This checks out because the rewrite on the right hand side of the (+-) definition happens to normalize to concrete values instead of substitutions/coercions.
On the other hand, if we'd like to stick with the original definition for (+-), then the rewrite doesn't go away, and we're in for a whole world of pain, because now we have to work with heterogeneous equalities. I did a proof with heterogeneous equalities in Agda, however I couldn't get it to work in Idris on short notice, and I believe making it work would be a rather painful experience. Here it is in Agda.
Note though that we would have to add one more case to the original definition in order to make proving properties about it feasible in the first place. That's because it doesn't pass the coverage checker as it is. It's evident to us that Fin 1 only has FZ as constructor, but this has to be also explained to the compiler:
(+-) : Fin (S n) -> Fin (S m) -> Fin (S (n + m))
(+-) {n} {m} FZ f' = rewrite plusCommutative n m in weakenN n f'
(+-) {n = Z} (FS FZ) f' impossible
(+-) {n = S n} (FS f) f' = FS (f +- f')
I can write the function
powApply : Nat -> (a -> a) -> a -> a
powApply Z f = id
powApply (S k) f = f . powApply k f
and prove trivially:
powApplyZero : (f : _) -> (x : _) -> powApp Z f x = x
powApplyZero f x = Refl
So far, so good. Now, I try to generalize this function to work with negative exponents. Of course, an inverse must be provided:
import Data.ZZ
-- Two functions, f and g, with a proof that g is an inverse of f
data Invertible : Type -> Type -> Type where
MkInvertible : (f : a -> b) -> (g : b -> a) ->
((x : _) -> g (f x) = x) -> Invertible a b
powApplyI : ZZ -> Invertible a a -> a -> a
powApplyI (Pos Z) (MkInvertible f g x) = id
powApplyI (Pos (S k)) (MkInvertible f g x) =
f . powApplyI (Pos k) (MkInvertible f g x)
powApplyI (NegS Z) (MkInvertible f g x) = g
powApplyI (NegS (S k)) (MkInvertible f g x) =
g . powApplyI (NegS k) (MkInvertible f g x)
I then try to prove a similar statement:
powApplyIZero : (i : _) -> (x : _) -> powApplyI (Pos Z) i x = x
powApplyIZero i x = ?powApplyIZero_rhs
However, Idris refuses to evaluate the application of powApplyI, leaving the type of ?powApplyIZero_rhs as powApplyI (Pos 0) i x = x (yes, Z is changed to 0). I've tried writing powApplyI in a non-pointsfree style, and defining my own ZZ with the %elim modifier (which I don't understand), but neither of these worked. Why isn't the proof handled by inspecting the first case of powApplyI?
Idris version: 0.9.15.1
Here are some things:
powApplyNI : Nat -> Invertible a a -> a -> a
powApplyNI Z (MkInvertible f g x) = id
powApplyNI (S k) (MkInvertible f g x) = f . powApplyNI k (MkInvertible f g x)
powApplyNIZero : (i : _) -> (x : _) -> powApplyNI 0 i x = x
powApplyNIZero (MkInvertible f g y) x = Refl
powApplyZF : ZZ -> (a -> a) -> a -> a
powApplyZF (Pos Z) f = id
powApplyZF (Pos (S k)) f = f . powApplyZF (Pos k) f
powApplyZF (NegS Z) f = f
powApplyZF (NegS (S k)) f = f . powApplyZF (NegS k) f
powApplyZFZero : (f : _) -> (x : _) -> powApplyZF 0 f x = x
powApplyZFZero f x = ?powApplyZFZero_rhs
The first proof went fine, but ?powApplyZFZero_rhs stubbornly keeps the type powApplyZF (Pos 0) f x = x. Clearly, there's some problem with ZZ (or my use of it).
The problem: powApplyI was not provably total, according to Idris. Idris' totality checker relies on being able to reduce parameters to structurally smaller forms, and with raw ZZs, this doesn't work.
The answer is to delegate the recursion to plain old powApply (which is proven total):
total
powApplyI : ZZ -> a <~ a -> a -> a
powApplyI (Pos k) (MkInvertible f g x) = powApply k f
powApplyI (NegS k) (MkInvertible f g x) = powApply (S k) g
Then, with a case split on i, powApplyIZero is proven trivially.
Thanks to Melvar from the #idris IRC channel.
powApplyI (Pos Z) i x doesn't reduce further because i is not in weak head normal form.
I don't have an Idris compiler, so I rewrote your code in Agda. It's pretty similar:
open import Function
open import Relation.Binary.PropositionalEquality
open import Data.Nat
open import Data.Integer
data Invertible : Set -> Set -> Set where
MkInvertible : {a b : Set} (f : a -> b) -> (g : b -> a) ->
(∀ x -> g (f x) ≡ x) -> Invertible a b
powApplyI : {a : Set} -> ℤ -> Invertible a a -> a -> a
powApplyI ( + 0 ) (MkInvertible f g x) = id
powApplyI ( + suc k ) (MkInvertible f g x) = f ∘ powApplyI ( + k ) (MkInvertible f g x)
powApplyI -[1+ 0 ] (MkInvertible f g x) = g
powApplyI -[1+ suc k ] (MkInvertible f g x) = g ∘ powApplyI -[1+ k ] (MkInvertible f g x)
Now you can define your powApplyIZero as
powApplyIZero : {a : Set} (i : Invertible a a) -> ∀ x -> powApplyI (+ 0) i x ≡ x
powApplyIZero (MkInvertible _ _ _) _ = refl
Pattern-matching on i induces unification and powApplyI (+ 0) i x becomes replaced with powApplyI (+ 0) i (MkInvertible _ _ _), so powApplyI can proceed further.
Or you could write this explicitly:
powApplyIZero : {a : Set} (f : a -> a) (g : a -> a) (p : ∀ x -> g (f x) ≡ x)
-> ∀ x -> powApplyI (+ 0) (MkInvertible f g p) x ≡ x
powApplyIZero _ _ _ _ = refl
I'm trying to make an Idris function of type (j : Nat) -> {auto p : So (j < n)} -> Fin n to convert a Nat into a Fin n. To get the Z case to work (and output FZ), I'm trying to prove that a proof of 0 < n is sufficient to be able to make FZ : Fin n. But I can't work out how to do this.
I'm open to making a completely different function, as long as it can convert Nat values into Fin n values (where they exist). My goal is to have some other function that can convert any Nat into a Mod n value, so that, for example, 15 : Nat is mapped to 3 : Mod 4. My Mod type currently has a single constructor, mkMod : Fin n -> Mod n.
After learning about LT : Nat -> Nat -> Type, I took a different approach. I started with the declaration:
natToFin : (j : Nat) -> {auto p : j `LT` n} -> Fin n
natToFin {n} j {p} = ?natToFin_rhs_1
. Case-splitting on n, then on p in the n = Z case resulted in:
natToFin : (j : Nat) -> {auto p : j `LT` n} -> Fin n
natToFin {n = (S k)} j {p = p} = ?natToFin_rhs_2
, which is essentially the proof I was asking for. From there, I case-split on j and filled the zero case, leaving:
natToFin : (j : Nat) -> {auto p : j `LT` n} -> Fin n
natToFin {n = (S k)} Z = FZ
natToFin {n = (S k)} (S j) {p = p} = ?natToFin_rhs_3
. I wanted to fill ?natToFin_rhs_3 with FS (natToFin j), but the type checker wasn't letting me. However, after a case split on p, it was fine:
natToFin : (j : Nat) -> {auto p : j `LT` n} -> Fin n
natToFin {n = (S k)} Z = FZ
natToFin {n = (S k)} (S j) {p = (LTESucc x)} = FS (natToFin j)
Finally, I added total, and it all checked out.
The only problem now is that Idris can't seem to find LT proofs automatically. This is what happens:
λΠ> the (Fin 6) (natToFin 2)
When elaborating argument p to function mod2.natToFin:
Can't solve goal
LT (fromInteger 2) (fromInteger 6)
Is there any way to fix that?