Type checking for Vectors in Idris - idris

From REPL how does not ensures that the a list is indeed interpret as a vector instead?
For example if I type:
:t Vect
I get Vect : Nat -> Type -> Type which makes absolute sense, if I type
:t Vect 2
I get Vect : Type -> Type which makes again absolute sense. But I try now:
:t Vect 2 [1,2]
and get an error
Can't disambiguate since no name has a suitable type:
Prelude.List.::, Prelude.Stream.::, Data.Vect.::
I was hoping to see instead [1,2] : Vect 2 Int instead. What I am doing wrong? I also have issues when using the function the when trying to interpret a list as vector.
Any suggestion?

the : (a : Type) -> a -> a takes a type and a value of that type and returns that value. So if the target type cannot be inferred from context, like in the REPL, you can use the (Vect 2 Int) [1,2] to specify what you mean with [1,2].
(Vect 2 [1,2] tries to use the List, Stream or Vect [1,2] as the argument in Vect 2 : Type -> Type. But unlike e.g. Int, the list [1,2] is not a Type, so that throws you that error.)

Related

Idris Dependent Pairs: Unexpected behavior between compiled program and REPL

When practicing using dependent pairs in Idris, I have encountered an unexpected difference in behavior between compiled programs and the REPL. The following datatype is what I am testing with:
(a : Type ** b : Type ** Arrow a b)
Which should represent some relation between type a and type b. Given an instance of the above, I would like to extract the "proof" term of the type. I can do this from the REPL with DPair.snd $ DPair.snd <some-instance> and everything works fine. However, if I try to make a function:
unwrap : (a ** b ** Arrow a b) -> Arrow a b
unwrap x = DPair.snd $ DPair.snd x
the program will compile, but will fail when I try to call it. The error message returned is
(input): No such variable b
Has anyone encountered this or knows of a solution?
What you want to achieve is not possible. If you look at the type of unwrap : (a1 : Type ** b1 : Type ** Arrow a b) -> Arrow a b you see that it uses a different datatype than (a : Type ** b : Type ** Arrow a b). That's because the arguments a, b are quantified beforehand - setting the resulting type (which is also the difference to the REPL case; there you aren't bound to the arguments). So with :set showimplicit it is
Main.unwrap : {b : Type} -> {a : Type} ->
(a1 : Type ** b1 : Type ** Main.Arrow a b) ->
Main.Arrow a b
That's the thing about dependent pairs, you can't restrict them easily. Take a look at Vect.filter : (elem -> Bool) -> Vect len elem -> (p : Nat ** Vect p elem) - if we had a function like unwrap : (p : Nat ** Vect p elem) -> Vect p elem, we wouldn't need dependent pair in the first place.
Instead, a function that would call unwrap would need to inspect p and then handle the Vect accordingly. Sadly, we can't easily inspect types (at least if you want to generalize for all types). So your best bet is: don't use dependent types here.
I realise I'm a year and a half late, but... This absolutely is possible! You just need to remember that the type a ** P is just syntactic sugar for DPair a (\x => P a); in the latter form, nothing special is going on whatsoever and so you can use your a and b just like you'd expect. We can also gain insight from how DPair.snd is typed in the standard library:
Idris> :t DPair.snd
snd : (x : DPair a P) -> P (fst x)
So, to extract the a-value from our pair, we simply call fst on that pair. How intuitive! (fst itself simply has the type DPair a P -> a). To get the b-value, which is the first value of the second part of our pair, we call fst . snd on the outermost pair. Therefore, your function should look like:
unwrap : (x : DPair a (DPair b . Arrow)) -> Arrow (fst x) (snd $ fst x)
unwrap x = snd (snd x)
(or, equivalently:)
unwrap : (x : DPair a (\theA => DPair b (\theB => Arrow theA theB))) -> ...
For whatever reason, unwrap = DPair.snd . DPair.snd doesn't work... but that's not too much of an issue.

Why is this mutually recursive data definition not total and how can I fix it?

I am experimenting with Idris a lot lately and came up with the following "type level definition of a set":
mutual
data Set : Type -> Type where
Empty : Set a
Insert : (x : a) -> (xs : Set a) -> Not (Elem x xs) -> Set a
data Elem : (x : a) -> Set a -> Type where
Here : Elem x (Insert x xs p)
There : Elem x xs -> Elem x (Insert y xs p)
So a set is either empty or it consists of a set and an additional element that is proven not to be in that set already.
When I totality check this, I get the error
[...] is not strictly positive
for Insert, Here and There. I have been searching the documentation for terms like "strictly positive" and the totality checker in general, but I cannot figure out why this case in particular is not total (or strictly positive). Can somebody explain this?
The natural next question then is of course how to "fix" it. Can I somehow change the definition, keeping its semantics, so that it totality checks?
Since I don't really need the definition to look like this (it is only an experiment after all) it would also be interesting to know whether there is another, somehow more idiomatic way to represent Sets at the type level that is total.
This SO post explains what strictly positive types are and why they matter. In your case, since Not (Elem x xs) simply means a function Elem x xs -> Void, this is where the "type being defined occurring on the left-hand side of an arrow" comes from.
Can you make do with something like this?
mutual
data Set : Type -> Type where
Empty : Set a
Insert : (x : a) -> (xs : Set a) -> NotElem x xs -> Set a
data NotElem : (x : a) -> Set a -> Type where
NotInEmpty : NotElem x Empty
NotInInsert : Not (x = y) -> NotElem x ys -> NotElem x (Insert y ys p)

How to specify a number range as a type in Idris?

I've been experimenting with Idris and it seems like it should be simple to specify some sort of type for representing all numbers between two different numbers, e.g. NumRange 5 10 is the type of all numbers between 5 and 10. I'd like to include doubles/floats, but a type for doing the same with integers would be equally useful. How would I go about doing this?
In practice, you may do better to simply check the bounds as needed, but you can certainly write a data type to enforce such a property.
One straightforward way to do it is like this:
data Range : Ord a => a -> a -> Type where
MkRange : Ord a => (x,y,z : a) -> (x >= y && (x <= z) = True) -> Range y z
I've written it generically over the Ord typeclass, though you may need to specialize it. The range requirement is expressed as an equation, so you simply supply a Refl when constructing it, and the property will then be checked. For example: MkRange 3 0 10 Refl : Range 0 10. One disadvantage of something like this is the inconvenience of having to extract the contained value. And of course if you want to construct an instance programmatically you'll need to supply the proofs that the bounds are indeed satisfied, or else do it in some context that allows for failure, like Maybe.
We can write a more elegant example for Nats without much trouble, since for them we already have a library data type to represent comparison proofs. In particular LTE, representing less-than-or-equal-to.
data InRange : Nat -> Nat -> Type where
IsInRange : (x : Nat) -> LTE n x -> LTE x m -> InRange n m
Now this data type nicely encapsulates a proof that n ≤ x ≤ m. It would be overkill for many casual applications, but it certainly shows how you might use dependent types for this purpose.

Idris - Use implicit variable inside function

How can we use an implicit variable inside a function? Reducing to the simplest possible case, is it possible to have:
dim : Vect n a -> Nat
dim vec = n
without getting the error:
When elaborating right hand side of rep:
No such variable n
Is there a way to access there values from inside? Or is it the same as asking for n inside sin n?
In this case, is it possible to prove that Vect is a "bijection" and recover the variables from there?
There is really no such variable n because it is not bounded by pattern matching.
You need to explicitly bring implicit variables in scope:
dim : Vect n a -> Nat
dim {n} vec = n
It is possible to view them in idris REPL:
*> :set showimplicits
*> :t dim
Main.dim : {n : Prelude.Nat.Nat} -> {a : Type} ->
(__pi_arg : Prelude.Vect.Vect n a) -> Prelude.Nat.Nat

Equality testing without explicit proof that data constructors are injective

Is it possible to define a simple syntactic notion of equality (similar to what GHC might automatically derive as the Eq instance for a Haskell 98 type), without either explicitly proving that each data constructor is injective, or doing something analogous, such as defining the retraction of each constructor and using cong?
In other words, is it possible to exploit the injectivity of data constructors more directly, rather than having to introduce one auxiliary function per constructor?
The following uses the natural numbers as an example.
module Eq where
open import Function
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary
data ℕ : Set where
zero : ℕ
suc : ℕ → ℕ
-- How to eliminate these injectivity proofs?
suc-injective : ∀ {n m} → suc n ≡ suc m → n ≡ m
suc-injective refl = refl
_≟_ : Decidable {A = ℕ} _≡_
zero ≟ suc _ = no (λ ())
suc _ ≟ zero = no (λ ())
zero ≟ zero = yes refl
suc n ≟ suc m with n ≟ m
suc n ≟ suc .n | yes refl = yes refl
... | no n≢m = no (n≢m ∘ suc-injective)
One could replace suc-injective by cong (λ { zero → zero ; (suc x) → x }), i.e. by defining a function which inverts suc, but that still requires boilerplate of one auxiliary function per constructor, and such functions are somewhat ugly to define because of the need to be total.
(Usual caveats re. missing something obvious apply.)
Ulf Norell's prelude for Agda contains a mechanism for automatically deriving decidable equality for a given datatype. The code is based on Agda's reflection mechanism and automatically generated extended lambdas for proving injectivity of constructors. I recommend taking a look at the code, even though it's not always as simple as it could be.