The book Type Driven Development with Idris presents this exercise:
Define a possible method that fits the signature:
two : (xs : Vect n elem) -> Vect (n * 2) elem
I tried:
two : (xs : Vect n elem) -> Vect (n * 2) elem
two xs = xs ++ xs
But I got the following error:
*One> :r
Type checking ./One.idr
One.idr:9:5:When checking right hand side of two:
Type mismatch between
Vect (n + n) elem (Type of xs ++ xs)
and
Vect (mult n 2) elem (Expected type)
Specifically:
Type mismatch between
plus n n
and
mult n 2
Holes: Hw1.two
If I have a Vector of size N, and need a Vector of size N*2, then appending it to itself seems reasonable.
What am I doing wrong?
Short answer
Change the type signature to
two : (xs : Vect n elem) -> Vect (n + n) elem
.If you really need it that way
Getting to
Vect (n * 2) elem
is a bit complicated. Here:The reason you got that error message is that equality in typechecking is equality after reduction to normal form.
n + n
andmult n 2
are equal, but their normal forms aren't. (mult n 2
is whatn * 2
reduces to after resolving the typeclass.)You can see the definition of
mult
like so:It works by pattern matching on the first argument. Since the first argument in the type signature of
two
isn
,mult
can't be reduced at all.multCommutative
will help us flip it around:Our best tool to apply that equality is
rewrite
, like in my definition oftwo'
. (run:t replace
at the REPL if you want to see how to do it the hard way) In therewrite foo in bar
construction,foo
is something of typea = b
andbar
has the type of the outer expression, but with alla
s replaced byb
s. In mytwo'
above, I first used it to changeVect (n * 2)
toVect (2 * n)
. This letsmult
reduce. If we look atmult
above, and apply it to2
i.e.S (S Z)
andn
, you getplus n (mult (S Z) n
, and thenplus n (plus n (mult Z n))
, and thenplus n (plus n Z)
. You don't have to work out the reduction yourself, you can just apply the rewrite and put a hole on the end:Then ask Idris:
plus n Z
doesn't reduce becauseplus
is defined by recursion on its first argument, just likemult
.plusZeroRightNeutral
gets you the equality you need:I used the same technique with
rewrite
again.:search
will let you search the library for inhabitants of a given type. You'll often find someone has done the work of proving things for you.(This answer is for Idris version 0.9.20.1)