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

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.

Related

Rewiring my own Vect but encountering issues

I was trying to re-implement the Vect data type to become more familiar with the dependent types. This is what I wrote:
data Vect : (len : Nat) -> (elem : Type) -> Type where
Nil : Vect Z elem
(::) : (x : elem) -> (xs : Vect len elem) -> Vect (S len) elem
append : Vect n elem -> Vect m elem -> Vect (n + m) elem
append [] y = y
append (x :: xs) y = x :: append xs y
I can define, for example Vect 4 Nat and others as well. But if I try append (Vect 4 Nat) (Vect 3 Nat) I get an error that I am not able to parse:
When checking an application of function Main.append:
Type mismatch between
Type (Type of Vect len elem)
and
Vect n elem (Expected type)
Clearly there is something wrong in the way I think about this.
Any suggestion?
Also when I try to create Vect 4 [1,2,3,4] I get an error:
When checking argument elem to type constructor Main.Vect:
Can't disambiguate since no name has a suitable type:
Prelude.List.::, Main.::, Prelude.Stream.::
So I guess I am quite lost ...
Your definition of Vect and append look fine to me, but it's how you're creating values that's the problem. You're mixing up the type constructor Vect with the data constructors Nil and ::. You should create values of type Vect len elem with calls to Nil and ::.
In particular, Vect 4 Nat is a type, but append expects a value of that type, like 1 :: 2 :: 3 :: 4 :: Nil (or [1,2,3,4] which is just syntactic sugar for the former).
And Vect 4 [1,2,3,4] isn't possible since [1,2,3,4] is a value not a Type

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.

Proving an index is within list bounds given (index + 1) is within bounds

Let's say we have a list : List a, and we want to use its first and second elements:
case inBounds 1 list of
Yes prf => doSmth (index 0 list) (index 1 list)
No _ => doSmthElse
Unfortunately, this does not typecheck: indeed, prf is a proof that InBounds 1 list holds, but while it's obvious to us humans that InBounds 0 list immediately follows, it still needs to be shown to the typechecker.
Of course, one might write a helper proof
inBoundsDecr : InBounds (S k) xs -> InBounds k xs
inBoundsDecr {k = Z} (InLater y) = InFirst
inBoundsDecr {k = (S k)} (InLater y) = InLater (inBoundsDecr y)
and then use it in the Yes branch like this:
case inBounds 1 list of
Yes prf => let prf' = inBoundsDecr prf in
doSmth (index 0 list) (index 1 list)
No _ => doSmthElse
but it seems to be quite verbose.
So, what's the most concise and/or idiomatic way to do this in Idris?
If you have a proof of xs that gives you some information about xs, it is better to use with instead of a case. Then the compiler can see that the argument can be determined by the proof. See this chapter in the tutorial: Views and the "with" rule
addHs : List Nat -> Nat
addHs xs with (inBounds 1 xs)
addHs xs | p = ?hole
Pattern-matching on p gives Yes prf, then Yes (InLater y), then Yes (InLater InFirst), and updating xs to (x :: y :: xs). And so you can easily use x and y:
addHs : List Nat -> Nat
addHs xs with (inBounds 1 xs)
addHs (x :: y :: xs) | (Yes (InLater InFirst)) = x + y
addHs xs | (No contra) = 0
The problem with that is – here it doesn't work properly. If you check if addHs is total, the compiler warns you, because it thinks that another Yes (InLater p) could be reached. Not sure why, the totality checker isn't that great. But in theory it should work fine. :-)
Other than your initial attempt (which may be more verbose, but you don't depend that much on the totality checker), you could of course add a dummy Yes (InLater p) case or stop there and do something like
addHs : List Nat -> Nat
addHs xs with (inBounds 1 xs)
addHs (x :: xs) | (Yes (InLater prf)) = x + (index 0 xs)
addHs xs | (No contra) = 0
Or being somewhat unsafe and assert that the case is unreachable:
addHs : List Nat -> Nat
addHs xs with (inBounds 1 xs) proof q
addHs (x :: y :: xs) | Yes (InLater InFirst) = x + y
addHs (x :: xs) | Yes (InLater p) = assert_unreachable
addHs xs | No _ = 0

Inf value is automatically forced after pattern matching

Let's say we have an infinite list:
data InfList : Type -> Type where
(::) : (value : elem) -> Inf (InfList elem) -> InfList elem
And we want to have finite number of its elements:
getPrefix : (count : Nat) -> InfList a -> List a
getPrefix Z _ = []
getPrefix (S k) (value :: xs) = value :: getPrefix k (?rest)
So, what is left:
a : Type
k : Nat
value : a
xs : InfList a
--------------------------------------
rest : InfList a
It turned out that after pattern matching xs become InfList a instead of Inf (InfList a).
Is there a way to have xs delayed?
It seems to be delayed anyway.
If you execute :x getPrefix 10 one with
one : InfList Int
one = 1 :: one
you get 1 :: getPrefix 9 (1 :: Delay one)
I can't find it anymore in the documentation but idris seems to insert Delay automatically.
Just try to add Delay constructor manually. It's removed implicitly.
getPrefix : (count : Nat) -> InfList a -> List a
getPrefix Z _ = []
getPrefix (S k) (value :: Delay xs) = value :: getPrefix k xs

Why doesn't this use of Elem typecheck?

I am quite confused.
module Experiment
import Data.Vect
p1: Elem 5 [3,4,5,6]
p1 = There (There Here)
v : Vect 4 Int
v = 3 :: 4 :: 5 :: 6 :: Nil
p2: Elem 5 v
p2 = There (There Here)
The definition of p2 does not typecheck, while the definition of p1 does. I am using Idris 0.10.2. Is there something I am missing?
Lowercase names in type declarations are interpreted as implicit arguments (like a in length : List a -> Nat which is actually length : {a : Type} -> List a -> Nat). To refer to the defined Vect you can either use an uppercase name or refer by the namespace:
module Experiment
import Data.Vect
A : Vect 4 Int
A = 3 :: 4 :: 5 :: 6 :: Nil
p2: Elem 5 A
p2 = There (There Here)
a : Vect 4 Int
a = 3 :: 4 :: 5 :: 6 :: Nil
p3: Elem 5 Experiment.a
p3 = There (There Here)