Proving Not (Elem x xs) when x and xs are statically known - idris

In Chapter 9 of Type Driven Development with Idris, we are introduced to the Elem predicate with constructors Here and There for proving that an element is a member of a vector. e.g.
oneInVector : Elem 1 [1, 2, 3]
oneInVector = Here
twoInVector : Elem 2 [1, 2, 3]
twoInVector = There Here
I'm wondering how to show that an element is not in a vector. It should perhaps be by providing a solution to this type:
notThere : Elem 4 [1, 2, 3] -> Void
notThere = ?rhs
Expression/Proof search does not come up with the answer in this case, giving:
notThere : Elem 4 [1,2,3] -> Void
notThere = \__pi_arg => ?rhs1
Scanning through the library for Data.Vect, these definitions look useful (but I'm not sure how to connect the dots):
||| Nothing can be in an empty Vect
noEmptyElem : {x : a} -> Elem x [] -> Void
noEmptyElem Here impossible
Uninhabited (Elem x []) where
uninhabited = noEmptyElem

The Elem relation is Decidable (if the element type has Decidable Equality itself), using isElem:
isElem : DecEq a => (x : a) -> (xs : Vect n a) -> Dec (Elem x xs)
The idea is to use isElem 4 [1, 2, 3] to have Idris compute the proof of Not (Elem 4 [1, 2, 3]). We'll need to build up some machinery similar to Agda's Relation.Nullary.Decidable.toWitnessFalse so that we can extract proofs from (negative) Dec results:
fromFalse : (d : Dec p) -> {auto isFalse : decAsBool d = False} -> Not p
fromFalse (Yes _) {isFalse = Refl} impossible
fromFalse (No contra) = contra
and then we can use this in your notThere definition:
notThere : Not (Elem 4 [1, 2, 3])
notThere = fromFalse (isElem 4 [1, 2, 3])

Rather than specifying my own rhs for notThere, it's better to use Idris' editor support:
Starting with:
notThere : Elem 4 [1, 2, 3] -> Void
Add definition on notThere:
notThere : Elem 4 [1, 2, 3] -> Void
notThere x = ?notThere_rhs
Case split on x:
notThere : Elem 4 [1, 2, 3] -> Void
notThere (There later) = ?notThere_rhs
Case split on later:
notThere : Elem 4 [1, 2, 3] -> Void
notThere (There (There later)) = ?notThere_rhs
Case split on later:
notThere : Elem 4 [1, 2, 3] -> Void
notThere (There (There There later))) = ?notThere_rhs
Case split on later:
notThere : Elem 4 [1,2,3] -> Void
notThere (There (There (There Here))) impossible
notThere (There (There (There (There _)))) impossible
This definition is total and so we're done:
*Elem> :total notThere
Main.notThere is Total
I'd still be interested if there's a nicer solution that uses the noEmptyElem and/or uninhabited from Data.Vect.

Related

splitEvery function for Vect in Idris

In Idris I am trying to write a type-safe(r) version of a splitEvery function for Vect, that on Lists looks like this:
splitEvery : Nat -> List a -> List (List a)
splitEvery _ [] = []
splitEvery n xs = (take n xs) ++ splitEvery n (drop n xs)
So far I've got:
splitEvery : {k : Nat} -> (n : Nat) -> Vect (k * n) a -> Vect k (Vect n a)
splitEvery {k = Z} _ [] = []
splitEvery {k = (S j)} n xs = (take n xs) :: splitEvery {k = j} n (drop n xs)
which will type-check and load in the REPL alright, but when I try to invoke it, it will fail:
*Main> splitEvery 2 (fromList [1..10])
(input):1:1-31:When checking an application of function Main.splitEvery:
Type mismatch between
Vect (length (enumFromTo 1 10))
Integer (Type of fromList (enumFromTo 1 10))
and
Vect (k * 2) Integer (Expected type)
Specifically:
Type mismatch between
length (enumFromTo 1 10)
and
mult k 2
So obviously Idris isn't seeing that a valid choice of k here would be 5. A way to make it work would be to explicitly give it the implicit parameter k, but that's ugly:
*Main> splitEvery {k = 5} 2 (fromList [1..10])
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]] : Vect 5 (Vect 2 Integer)
So my question is: is there a way to make this work that isn't ugly, or is more idiomatic than what I've produced so far?
Idris is only failing to infer the value of k in the REPL for some reason. If you amend your code with
result: Vect 5 (Vect 2 Nat)
result = splitEvery 2 (fromList [1..10])
everything typechecks - as the type is already known and k can be infered. You can achieve the same on the REPL by providing a type hint using the:
the (Vect 5 (Vect 2 Nat)) (splitEvery 2 (fromList [1..10])) works as well.

In Idris, what's the type of a list of lists of doubles, where all the lengths are known?

An example value: [[1, 2], [1]]
Here, I would know that there are 2 lists, and that the first list has length 2, while the second one has length 1. Ideally, this function would compute those types:
func : (n ** Vect n Nat) -> Type
But I don't know how to write it. I'm pretty sure it's something to do with dependent pairs, but I'm not sure how to write it.
To clarify, I know it'd be possible to simply use (n ** Vect n (p ** Vect p Double)) as the type of the example value. However, n only constrains the number of lists, not the number of their elements, because inside the list, p could be anything. I would most likely need something where the first element of the dependent pair is a vector of lengths, not just the number of lists. So something like (Vect n Nat ** Vect n (Vect m Double))--where each m is the corresponding element of the first vector.
You could define a new vector type which contains possibly differently indexed elements of an indexed type at each position:
import Prelude
import Data.Vect
-- heterogeneously indexed vector
data IVect : Vect n ix -> (ix -> Type) -> Type where
Nil : IVect Nil b
(::) : b i -> IVect is b -> IVect (i :: is) b
-- of which a special case is a vector of vectors
VVect : Vect n Nat -> Type -> Type
VVect is a = IVect is (flip Vect a)
test1 : VVect [2, 2, 2] Nat
test1 = [[1, 2], [3, 4], [5, 6]]
test2 : VVect [0, 1, 2] Bool
test2 = [[], [True], [False, True]]
Alternatively, you can define VVect using dependent pairs and map, but this is more cumbersome to use:
VVect' : Vect n Nat -> Type -> Type
VVect' {n = n} is a = (xs : Vect n (m ** Vect m a) ** (map fst xs = is))
test3 : VVect' [0, 1, 2] Bool
test3 = ([(_ ** []), (_ ** [True]), (_ ** [False, False])] ** Refl)
You have some choice though whether to use lists or vectors. With lists as the inner container, values look more compact:
VVect'' : Vect n Nat -> Type -> Type
VVect'' {n = n} is a = (xs : Vect n (List a) ** (map length xs = is))
test4 : VVect'' [0, 1, 2] Bool
test4 = ([[], [True], [False, True]] ** Refl)

Idris - map an operation on a n-dimensional vector

I defined n-dimensional vectors in Idris as follows:
import Data.Vect
NDVect : (Num t) => (rank : Nat) -> (shape : Vect rank Nat) -> (t : Type) -> Type
NDVect Z [] t = t
NDVect (S n) (x::xs) t = Vect x (NDVect n xs t)
Then I defined the following function which maps a function f to every entry in the tensor.
iterateT : (f : t -> t') -> (v : NDVect r s t) -> NDVect r s t'
iterateT {r = Z} {s = []} f v = f v
iterateT {r = S n} {s = x::xs} f v = map (iterateT f) v
But when I try to call iteratorT in the following function:
scale : Num t => (c : t) -> (v : NDVect rank shape t) -> NDVect rank shape t
scale c v = iterateT (*c) v
I get the following error message saying there is a type mismatched, which seems pretty fine to me
When checking right hand side of scale with expected type
NDVect rank shape t
When checking argument v to function Main.iterateT:
Type mismatch between
NDVect rank shape t (Type of v)
and
NDVect r s t (Expected type)
Specifically:
Type mismatch between
NDVect rank shape t
and
NDVect r s t
Specifically:
Type mismatch between
NDVect rank shape t
and
NDVect r s t
I have also been wondering how to express n-dimensional vectors (i.e. tensors) in Idris. I had a play with the type definition in the question, but encountered various issues, so I expressed the NDVect function as a data type:
data NDVect : (rank : Nat) -> (shape : Vect rank Nat) -> Type -> Type where
NDVZ : (value : t) -> NDVect Z [] t
NDV : (values : Vect n (NDVect r s t)) -> NDVect (S r) (n::s) t
And implemented map as follows:
nmap : (t -> u) -> (NDVect r s t) -> NDVect r s u
nmap f (NDVZ value) = NDVZ (f value)
nmap f (NDV values) = NDV (map (nmap f) values)
The following now works:
*Main> NDVZ 5
NDVZ 5 : NDVect 0 [] Integer
*Main> nmap (+4) (NDVZ 5)
NDVZ 9 : NDVect 0 [] Integer
*Main> NDV [NDVZ 1, NDVZ 2, NDVZ 3]
NDV [NDVZ 1, NDVZ 2, NDVZ 3] : NDVect 1 [3] Integer
*Main> nmap (+4) (NDV [NDVZ 1, NDVZ 2, NDVZ 3])
NDV [NDVZ 5, NDVZ 6, NDVZ 7] : NDVect 1 [3] Integer
Unfortunately, having all the type constructors makes things a bit ugly. I'd love to know if there's a cleaner way to solve this.
Edit:
Here's a slightly shorter type signature that doesn't explicitly encode the tensor rank in the type:
data NDVect : (shape : List Nat) -> Type -> Type where
NDVZ : (value : t) -> NDVect [] t
NDV : (values : Vect n (NDVect s t)) -> NDVect (n::s) t
nmap : (t -> u) -> (NDVect s t) -> NDVect s u
nmap f (NDVZ value) = NDVZ (f value)
nmap f (NDV values) = NDV (map (nmap f) values)

List Equality w/ `cong`

Following my other question, I tried to implement the actual exercise in Type-Driven Development with Idris for same_cons to prove that, given two equal lists, prepending the same element to each list results in two equal lists.
Example:
prove that 1 :: [1,2,3] == 1 :: [1,2,3]
So I came up with the following code that compiles:
sameS : {xs : List a} -> {ys : List a} -> (x: a) -> xs = ys -> x :: xs = x :: ys
sameS {xs} {ys} x prf = cong prf
same_cons : {xs : List a} -> {ys : List a} -> xs = ys -> x :: xs = x :: ys
same_cons prf = sameS _ prf
I can call it via:
> same_cons {x=5} {xs = [1,2,3]} {ys = [1,2,3]} Refl
Refl : [5, 1, 2, 3] = [5, 1, 2, 3]
Regarding the cong function, my understanding is that it takes a proof, i.e. a = b, but I don't understand its second argument: f a.
> :t cong
cong : (a = b) -> f a = f b
Please explain.
If you have two values u : c and v : c, and a function f : c -> d, then if you know that u = v, it has to follow that f u = f v, following simply from referential transparency.
cong is the proof of the above statement.
In this particular use case, you are setting (via unification) c and d to List a, u to xs, v to ys, and f to (:) x, since you want to prove that xs = ys -> (:) x xs = (:) x ys.

How does "There" work in the idris tutorial, page 11, section 3.4.4?

Here is the example from the tutorial, slightly modified for simplicity:
data Vect : Nat -> (b:Type) -> Type where
Nil : Vect Z a
(::) : a -> Vect k a -> Vect (S k) a
data Elem : a -> Vect n a -> Type where
Here : {x:a} -> {xs:Vect n a} -> Elem x (x :: xs)
There : {x,y:a} -> {xs:Vect n a} -> Elem x xs -> Elem x (y :: xs)
testVec : Vect 4 Int
testVec = 3 :: 4 :: 5 :: 6 :: Nil
inVect : Elem 4 testVec
inVect = There Here
I can't understand how There verifies that the value is correct.
As far as I understand it, There works like a function, so it takes the
element of type Here, which when filling in the holes, corresponds to Elem 3 testVec, then sets the first value of testVec to y, and the rest to xs. But since, y isn't used anywhere, I would except this not to cause any restriction.
However, when I try
inVectBroken : Elem 2 testVec
inVectBroken = There Here
I get an error:
When checking an application of constructor There:
Type mismatch between
Elem x (x :: xs) (Type of Here)
and
Elem 2 [4, 5, 6] (Expected type)
Specifically:
Type mismatch between
2
and
4
Can someone explain to me how the above code works (magically?) to restrict There to the tail of Vect?
Here 4 (x :: xs) is a proof that 4 is at the head of (x :: xs), so x = 4. There takes a proof Elem 4 xs that 4 is somewhere in xs and so proofs Elem 4 (y :: xs), that 4 is still somewhere down a extended list. That is where the y goes to. It does not matter what y actually is, it just allows to extend the proof to larger lists. For example:
in1 : Elem 4 (4 :: Nil)
in1 = Here
in2 : Elem 4 (3 :: 4 :: Nil)
in2 = There in1
in3 : Elem 4 (8 :: 4 :: Nil)
in3 = There in1
By the types you see that not the element 4 changes throughout the proof but the list.