How can I get Idris to unmap a vector in order to infer a type? - idris

I have the following working function:
unMaybe : (t : Type) -> {auto p : t = Maybe x} -> Type
unMaybe {x} _ = x
This function works fine:
> unMaybe (Maybe Int)
Int
I also have another similar function:
unMaybesA : (ts : Vect n Type) -> {xs : Vect n Type} -> {auto p : map Maybe xs = ts} -> Vect n Type
unMaybesA {xs} _ = xs
Unfortunately the following fails:
> unMaybesA [Maybe Int, Maybe String]
(input):1:1-35:When checking argument p to function Main.unMaybesA:
Can't find a value of type
Data.Vect.Vect n implementation of Prelude.Functor.Functor, method map Maybe
xs =
[Maybe Int, Maybe String]
But the following works:
> unMaybesA {xs=[_,_]} [Maybe Int, Maybe String]
[Int, String]
Is the a way to get Idris to automatically do {xs=[_,_]} with however many _ the vector has?
unMaybesB : (ts : Vect n Type) -> {auto p : (xs : Vect n Type ** map Maybe xs = ts)} -> Vect n Type
unMaybesB {p} _ = fst p
Possibly by using an elaborator script to automatically fill p in the function above?
I have the outline of an elab script below. I just need to figure out how to generate n, ts, and xs from the goal.
helper1 : Vect n Type -> Vect n Type -> Type
helper1 ts xs = (map Maybe xs) = ts
unMaybesC : (ts : Vect n Type) -> {auto p : DPair (Vect n Type) (helper1 ts)} -> Vect n Type
unMaybesC {p} _ = fst p
helper2 : (n : Nat) -> (ts : Vect n Type) -> (xs : Vect n Type) -> helper1 ts xs -> DPair (Vect n Type) (helper1 ts)
helper2 _ _ xs p = MkDPair xs p
q : Elab ()
q = do
let n = the Raw `(2 : Nat)
let ts = the Raw `(with Vect [Maybe String, Maybe Int])
let xs = the Raw `(with Vect [String, Int])
fill `(helper2 ~n ~ts ~xs Refl)
solve
qC : Vect 2 Type
qC = unMaybesC {p=%runElab q} [Maybe String, Maybe Int]

map Maybe xs = ts seems idiomatic, but is quite difficult. If you want to auto search for a non-simple proof, write an explicit proof type. Then the proof search will try the constructors and is guided in the right direction.
data IsMaybes : Vect n Type -> Vect n Type -> Type where
None : IsMaybes [] []
Then : IsMaybes xs ms -> IsMaybes (t :: xs) (Maybe t :: ms)
unMaybes : (ts : Vect n Type) -> {xs : Vect n Type} -> {auto p : IsMaybes xs ts} -> Vect n Type
unMaybes ts {xs} = xs
And with this:
> unMaybes [Maybe Nat, Maybe Int, Maybe (Maybe String)]
[Nat, Int, Maybe String] : Vect 3 Type

Related

How to prove equality commutes in Idris?

Trying to prove the following assertion:
equalityCommutesNat : (n : Nat) -> (m : Nat) -> n = m -> m = n
I found plusCommutes in the libraries but nothing for equality.
The only inhabitant of = is Refl : (a = a), so if you pattern match, you'll get evidence that n is m.
Which means you can then use Refl, since Idris's pattern matching now knows they're the same:
equalityCommutesNat : (n : Nat) -> (m : Nat) -> n = m -> m = n
equalityCommutesNat _ _ Refl = Refl
And you can play around with this in the REPL:
> equalityCommutesNat 1 1 Refl
Refl : 1 = 1

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

Why does Idris give me Type mismatch error for the following code?

I am a newbie trying to learn Idris and wanted to create a function test that returns a Vector whose type is parameterized by the function argument.
vecreplicate : (len : Nat) -> (x : elem) -> Vect len elem
vecreplicate Z x = []
vecreplicate (S k) x = x :: vecreplicate k x
test : (k:Nat) -> Nat -> Vect k Int
test Z = vecreplicate Z (toIntegerNat Z)
test k = vecreplicate k (toIntegerNat k)
When I try to compile the code with Idris I get the following type error
Type mismatch between
Vect len elem (Type of vecreplicate len x)
and
Nat -> Vect 0 Int (Expected type)
Specifically:
Type mismatch between
Vect len
and
\uv => Nat -> uv
Why am I getting this error?
test : (k:Nat) -> Nat -> Vect k Int takes two arguments, but you only match on k. That's why the expected type is a lambda (Nat -> Vect 0 Int). Just drop one Nat: test : (k : Nat) -> Vect k Int.
Also, toIntegerNat returns Integer not Int. :search Nat -> Int returns toIntNat, so that's what you want to use there.

Understanding `decEq`

Given:
*section3> :module Data.Vect
*section3> :let e = the (Vect 0 Int) []
*section3> :let xs = the (Vect _ _) [1,2]
*section3> decEq xs e
(input):1:7:When checking argument x2 to function Decidable.Equality.decEq:
Type mismatch between
Vect 0 Int (Type of e)
and
Vect 2 Integer (Expected type)
Specifically:
Type mismatch between
0
and
2
Why must the Nat arguments equal each other for DecEq?
Note - posted in https://groups.google.com/forum/#!topic/idris-lang/qgtImCLka3I originally
decEq is for homogenous propositional equality:
||| Decision procedures for propositional equality
interface DecEq t where
||| Decide whether two elements of `t` are propositionally equal
total decEq : (x1 : t) -> (x2 : t) -> Dec (x1 = x2)
As you can see, x1 and x2 are both of type t. In your case, you have x1 : Vect 2 Integer and x2 : Vect 0 Int. These are two different types.
You can write your own heterogenous equality decider for Vectors of the same element type by first checking their lengths, then delegating to the homogenous version:
import Data.Vect
vectLength : {xs : Vect n a} -> {ys : Vect m a} -> xs = ys -> n = m
vectLength {n = n} {m = n} Refl = Refl
decEqVect : (DecEq a) => (xs : Vect n a) -> (ys : Vect m a) -> Dec (xs = ys)
decEqVect {n = n} {m = m} xs ys with (decEq n m)
decEqVect xs ys | Yes Refl = decEq xs ys
decEqVect xs ys | No notEq = No (notEq . vectLength)

How can I arrange to pattern match on a dependent view?

I've written some simple types for viewing Vect values:
data SnocVect : Vect n a -> Type where
SnocNil : SnocVect []
Snoc : (xs : Vect n a) -> (x : a) -> SnocVect (xs ++ [x])
data Split : (m : Nat) -> Vect n a -> Type where
MkSplit : (xs : Vect j a) -> (ys : Vect k a) ->
Split j (xs ++ ys)
Now it seems to me entirely reasonable that if I have a Split separating the last element of a vector, I should be able to convert that into a SnocVect:
splitToSnocVect : .{xs : Vect (S n) a} -> Split n xs ->
SnocVect xs
Unfortunately, I can't seem to find any way to implement this thing. In particular, I haven't found any way whatsoever to get it to let me pattern match on the Split n xs argument, without which I obviously can't get anywhere. I think the basic problem is that I have something of type
Split j (ps ++ [p])
and since ++ isn't injective, I need to work some sort of magic to convince the type checker that things make sense. But I don't understand this well enough to say for sure.
I finally got it! I imagine there must be a better way, but this works.
vectLengthConv : {auto a : Type} -> m = n ->
Vect m a = Vect n a
vectLengthConv prf = rewrite prf in Refl
splitToSnocVect' : .(n : Nat) -> .(xs : Vect m a) ->
.(m = n+1) -> Split n xs -> SnocVect xs
splitToSnocVect' n (ys ++ zs) prf (MkSplit {k} ys zs)
with (vectLengthConv (plusLeftCancel n k 1 prf))
splitToSnocVect' n (ys ++ []) prf
(MkSplit {k = Z} ys []) | Refl impossible
splitToSnocVect' n (ys ++ (z :: [])) prf
(MkSplit {k = (S Z)} ys (z :: [])) | lenconv =
Snoc ys z
splitToSnocVect' n (ys ++ zs) prf
(MkSplit {k = (S (S k))} ys zs) | Refl impossible
splitToSnocVect : .{n : Nat} -> .{xs : Vect (S n) a} ->
Split n xs -> SnocVect xs
splitToSnocVect {n} {xs} splt =
splitToSnocVect' n xs (plusCommutative 1 n) splt
Edit
David Christiansen suggests nixing vectLengthConv and instead using cong {f=\len=>Vect len a} (plusLeftCancel n k 1 prf) in the with clause. This helps a little.