'half' function type signature in Idris - dependent-type

I'm pretty new to Idris and I'm trying to catch the basic concepts and syntax.
Even if it may sound pointless, I'm trying to define a half function which is halving a natural.
I wish to come up with something like:
half : (n : Nat) -> (k : Nat) -> (n = k + k) -> (k : Nat)
but of course it's not working. Specifically I get:
error: expected: dependent type signature
half : (n : Nat) -> (k : Nat) -> (n = k + k) -> (k : Nat)
Is it possible?
Thanks.

What you want is to express that half n is some Natural number k such that n = k + k holds. The way to do it is by using a sigma type, i.e. a dependent pair of a number k and a proof n = k + k (it's a dependent pair because the type of the second coordinate, n = k + k depends on the value of the first coordinate, k).
The Idris standard library defines DPair for depedent pairs, including some syntax sugar allowing you to write
half : (n : Nat) -> (k ** n = k + k)
However, note that you won't be able to implement half (as a total function) because there's no good answer to e.g. half 1. Maybe what you want is
half : (n : Nat) -> (k ** Either (n = k + k) (n = k + k + 1))
?

You shouldn't use k twice.
half : (n : Nat) -> (k : Nat) -> (n = k + k) -> Nat
is correct, but useless.
I think you need
half : (n : Nat) -> Maybe (k ** n = k + k)

Related

Proof inside nested constructor of recursive type

I am having some trouble with the code below. Essentially I want to create a slice type. The motivation comes from Python, where a slice is [start:end:step], used for slicing a sublist out of a list. This is conceptually the same as a sequence of indices [start, start+step, start+2*step, ..., end].
The way I've tried to capture it is Slice n can be applied to a Vect (n+m) a. The basic constructor FwdS will create a slice with a non-zero step (proof stepNZ). The SLen constructor will increment an existing slice's Vect size requirement by its step (computed using stepOf). Similarly SStart increments a slice's Vect size requirement by 1.
Then the final value conceptually corresponds to:
start := # of SStart in slice
stop := start + (# of SLen) * step
step := constructor argument in FwdS
If the slice is [start:stop:step].
mutual
data Slice : Nat -> Type where
FwdS : (step : Nat) -> {stepNZ : Not (step = Z)} -> Slice Z
SLen : (x : Slice len) -> Slice (len + (stepOf x))
SStart : Slice len -> Slice (S len)
stepOf : Slice n -> Nat
stepOf (FwdS step) = step
stepOf (SLen slice) = stepOf slice
stepOf (SStart slice) = stepOf slice
length : Slice n -> Nat
length (FwdS step ) = Z
length (SLen slice) = let step = stepOf slice
len = length slice
in len + step
length (SStart slice) = length slice
select : (slice: Slice n) -> Vect (n+m) a -> Vect (length slice) a
select (FwdS step) xs = []
select (SStart slice) (x :: xs) = select slice xs
select (SLen slice) (xs) = ?trouble
The trouble is in the last pattern. I'm not sure what the issue is - if I try to case split on xs I get both [] and (_::_) impossible. Ideally I'd like to have that case read something like this:
select (SLen slice) (x :: xs) = let rec = drop (stepOf slice) (x::xs)
in x :: (select slice rec)
and have Idris recognize that if the first argument is an SLen constructor, the second argument cannot be []. My intuition is that at the SLen level, Idris does not understand it already has a proof that stepOf slice is not Z. But I'm not sure how to test that idea.
My intuition is that at the SLen level, Idris does not understand it already has a proof that stepOf slice is not Z.
You are right. With :t trouble you see that the compiler doesn't have enough information to infer that (plus (plus len (stepOf slice)) m) is not 0.
a : Type
m : Nat
len : Nat
slice : Slice len
xs : Vect (plus (plus len (stepOf slice)) m) a
--------------------------------------
trouble : Vect (plus (length slice) (stepOf slice)) a
You would have to solve two problems: get a proof that stepOf slice is S k for some k like getPrf : (x : Slice n) -> (k ** stepOf x = (S k)), then rewrite Vect (plus (plus len (stepOf slice)) m) a to something like Vect (S (plus k (plus len m))) a so the compiler can at least know that this xs is not empty. But it doesn't get easier from thereon. :-)
Basically whenever you have a function where you use functions in the arguments, you probably can rewrite those informations into the type. Like select with length slice or SLen with stepOf x. Here is an example implementation:
data Slice : (start : Nat) -> (len : Nat) -> (step : Nat) -> (cnt : Nat) -> Type where
FwdS : (step : Nat) -> Slice Z Z step Z
SLen : Slice Z len step cnt -> Slice Z (S step + len) step (S cnt)
SStart : Slice start len step cnt -> Slice (S start) len step cnt
You gain a lot from this: you can access the parameters len and step directly without proving the functions length and stepOf first. Also you can have better control about your allowed data. For example, in your definiton SLen $ SStart $ SLen $ SStart $ FwdS 3 would have been valid, mixing steps and start increments.
select could look like this:
select : Slice start len step cnt -> Vect (start + len + m) a -> Vect cnt a
select (FwdS k) xs = []
select (SStart s) (x :: xs) = select s xs
select (SLen s) [] impossible
select (SLen s {step} {len} {cnt}) (x::xs) {m} {a} =
let is = replace (sym $ plusAssociative step len m) xs {P=\t => Vect t a} in
(x :: select s (drop step is))
If you want an exercise with proving, you could try to implement select : Slice start len step cnt -> Vect (len + start + m) a -> Vect cnt a, so switching start + len.
And getting two elements starting at 1 in steps of 4:
> select (SStart $ SLen $ SLen $ FwdS 3) [0,1,2,3,4,5,6,7,8,9]
[1, 5] : Vect 2 Integer

Check if Vector's Lengths are Equal

Given the following from Type-Driven Development with Idris:
import Data.Vect
data EqNat : (num1 : Nat) -> (num2 : Nat) -> Type where
Same : (num : Nat) -> EqNat num num
sameS : (eq : EqNat k j) -> EqNat (S k) (S j)
sameS (Same n) = Same (S n)
checkEqNat : (num1 : Nat) -> (num2 : Nat) -> Maybe (EqNat num1 num2)
checkEqNat Z Z = Just $ Same Z
checkEqNat Z (S k) = Nothing
checkEqNat (S k) Z = Nothing
checkEqNat (S k) (S j) = case checkEqNat k j of
Just eq => Just $ sameS eq
Nothing => Nothing
exactLength : (len : Nat) -> (input : Vect m a) -> Maybe (Vect len a)
exactLength {m} len input = case (checkEqNat m len) of
Just (Same m) => Just input
Nothing => Nothing
If I replace the last function's Just (Same m) with Just eq, the compiler complains:
*Lecture> :r
Type checking ./Lecture.idr
Lecture.idr:19:75:
When checking right hand side of Main.case block in exactLength at Lecture.idr:18:34 with expected type
Maybe (Vect len a)
When checking argument x to constructor Prelude.Maybe.Just:
Type mismatch between
Vect m a (Type of input)
and
Vect len a (Expected type)
Specifically:
Type mismatch between
m
and
len
Holes: Main.exactLength
How does Just (Same m), i.e. the working code, provide "evidence" that exactLength's len and m are equal?
What I find useful when working with Idris is adding holes when you're not sure about something rather than solving them. Like adding a hole into Just ... branch to see what's going on there:
exactLength : (len : Nat) -> (input : Vect m a) -> Maybe (Vect len a)
exactLength {m} len input = case (checkEqNat m len) of
Just (Same m) => ?hole
Nothing => Nothing
and then change (Same m) to eq and back while looking at the results of type checking. In the eq case it's like this:
- + Main.hole [P]
`-- a : Type
m : Nat
len : Nat
eq : EqNat m len
input : Vect m a
--------------------------------
Main.hole : Maybe (Vect len a)
And in the (Same m) case it's like this:
- + Main.hole_1 [P]
`-- m : Nat
a : Type
input : Vect m a
--------------------------------
Main.hole_1 : Maybe (Vect m a)
So eq is something of a type EqNat m len, no one knows whether it's inhabitant or not, while Same m (or Same len) is definitely inhabitant which proves that m and len are equal.
When you start with
exactLength : (len : Nat) -> (input : Vect m a) -> Maybe (Vect len a)
exactLength {m} len input with (_)
exactLength {m} len input | with_pat = ?_rhs
and gradually extend the missing links until you reached
exactLength : (len : Nat) -> (input : Vect m a) -> Maybe (Vect len a)
exactLength {m} len input with (checkEqNat m len)
exactLength {m = m} len input | Nothing = Nothing
exactLength {m = len} len input | (Just (Same len)) = Just input
you can see how idris can derive from the fact that checkEqNat m len returned a Just (Same ...) that it can then infer that {m = len}. AFAIK just writing Just eq is not a proof that eq is indeed inhabited.

(xs : Vect n elem) -> Vect (n * 2) elem

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:
two' : Vect n elem -> Vect (n * 2) elem
two' {n} xs = rewrite multCommutative n 2 in rewrite plusZeroRightNeutral n in xs ++ xs
The reason you got that error message is that equality in typechecking is equality after reduction to normal form. n + n and mult n 2 are equal, but their normal forms aren't. (mult n 2 is what n * 2 reduces to after resolving the typeclass.)
You can see the definition of mult like so:
*kevinmeredith> :printdef mult
mult : Nat -> Nat -> Nat
mult 0 right = 0
mult (S left) right = plus right (mult left right)
It works by pattern matching on the first argument. Since the first argument in the type signature of two is n, mult can't be reduced at all. multCommutative will help us flip it around:
*kevinmeredith> :t multCommutative
multCommutative : (left : Nat) ->
(right : Nat) -> left * right = right * left
Our best tool to apply that equality is rewrite, like in my definition of two'. (run :t replace at the REPL if you want to see how to do it the hard way) In the rewrite foo in bar construction, foo is something of type a = b and bar has the type of the outer expression, but with all as replaced by bs. In my two' above, I first used it to change Vect (n * 2) to Vect (2 * n). This lets mult reduce. If we look at mult above, and apply it to 2 i.e. S (S Z) and n, you get plus n (mult (S Z) n, and then plus n (plus n (mult Z n)), and then plus 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:
two' : Vect n elem -> Vect (n * 2) elem
two' {n} xs = rewrite multCommutative n 2 in ?aaa
Then ask Idris:
*kevinmeredith> :t aaa
elem : Type
n : Nat
xs : Vect n elem
_rewrite_rule : plus n (plus n 0) = mult n 2
--------------------------------------
aaa : Vect (plus n (plus n 0)) elem
plus n Z doesn't reduce because plus is defined by recursion on its first argument, just like mult. plusZeroRightNeutral gets you the equality you need:
*kevinmeredith> :t plusZeroRightNeutral
plusZeroRightNeutral : (left : Nat) -> left + 0 = left
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.
*kevinmeredith> :s (n : Nat) -> n + 0 = n
= Prelude.Nat.multOneLeftNeutral : (right : Nat) ->
fromInteger 1 * right = right
= Prelude.Nat.plusZeroRightNeutral : (left : Nat) ->
left + fromInteger 0 = left
*kevinmeredith> :s (n, m : Nat) -> n * m = m * n
= Prelude.Nat.multCommutative : (left : Nat) ->
(right : Nat) -> left * right = right * left
(This answer is for Idris version 0.9.20.1)

In Idris, how to write a "vect generator" function that take a function of index in parameter

I'm trying to write in Idris a function that create a Vect by passing the size of the Vect and a function taking the index in parameter.
So far, I've this :
import Data.Fin
import Data.Vect
generate: (n:Nat) -> (Nat -> a) ->Vect n a
generate n f = generate' 0 n f where
generate': (idx:Nat) -> (n:Nat) -> (Nat -> a) -> Vect n a
generate' idx Z f = []
generate' idx (S k) f = (f idx) :: generate' (idx + 1) k f
But I would like to ensure that the function passed in parameter is only taking index lesser than the size of the Vect.
I tried that :
generate: (n:Nat) -> (Fin n -> a) ->Vect n a
generate n f = generate' 0 n f where
generate': (idx:Fin n) -> (n:Nat) -> (Fin n -> a) -> Vect n a
generate' idx Z f = []
generate' idx (S k) f = (f idx) :: generate' (idx + 1) k f
But it doesn't compile with the error
Can't convert
Fin n
with
Fin (S k)
My question is : is what I want to do possible and how ?
The key idea is that the first element of the vector is f 0, and for the tail, if you have k : Fin n, then FS k : Fin (S n) is a "shift" of the finite number that increments its value and its type at the same time.
Using this observation, we can rewrite generate as
generate : {n : Nat} -> (f : Fin n -> a) -> Vect n a
generate {n = Z} f = []
generate {n = S _} f = f 0 :: generate (f . FS)
Another possibility is to do what #dfeuer suggested and generate a vector of Fins, then map f over it:
fins : (n : Nat) -> Vect n (Fin n)
fins Z = []
fins (S n) = FZ :: map FS (fins n)
generate' : {n : Nat} -> (f : Fin n -> a) -> Vect n a
generate' f = map f $ fins _
Proving generate f = generate' f is left as en exercise to the reader.
Cactus's answer appears to be about the best way to get what you asked for, but if you want something that can be used at runtime, it will be quite inefficient. The essential reason for this is that to weaken a Fin n to a Fin n+m requires that you completely deconstruct it to change the type of its FZ, and then build it back up again. So there can be no sharing at all between the Fin values produced for each vector element. An alternative is to combine a Nat with a proof that it is below a given bound, which leads to the possibility of erasure:
data NFin : Nat -> Type where
MkNFin : (m : Nat) -> .(LT m n) -> NFin n
lteSuccLeft : LTE (S n) m -> LTE n m
lteSuccLeft {n = Z} prf = LTEZero
lteSuccLeft {n = (S k)} {m = Z} prf = absurd (succNotLTEzero prf)
lteSuccLeft {n = (S k)} {m = (S j)} (LTESucc prf) = LTESucc (lteSuccLeft prf)
countDown' : (m : Nat) -> .(m `LTE` n) -> Vect m (NFin n)
countDown' Z mLTEn = []
countDown' (S k) mLTEn = MkNFin k mLTEn :: countDown' k (lteSuccLeft mLTEn)
countDown : (n : Nat) -> Vect n (NFin n)
countDown n = countDown' n lteRefl
countUp : (n : Nat) -> Vect n (NFin n)
countUp n = reverse $ countDown n
generate : (n : Nat) -> (NFin n -> a) -> Vect n a
generate n f = map f (countUp n)
As in the Fin approach, the function you pass to generate does not need to work on all naturals; it only needs to handle ones less than n.
I used the NFin type to explicitly indicate that I want the LT m n proof to be erased in all cases. If I didn't want/need that, I could just use (m ** LT m n) instead.

How do I provide an implicit argument explicitly?

Suppose I have a function with this signature:
myNatToFin : (m : Nat) -> (n : Nat) -> { auto p : n `GT` m } -> Fin n
I try to apply it like this myNatToFin k (S k) in the body of another function and I get the error:
Can't solve goal
GT (S k) k
So, I believe I have to explicitly pass a proof that GT (S k) k, but I have no idea how to do this. How can I explicitly pass the implicit proof argument so that this compiles?
You can give explicit arguments for implicit parameters by enclosing them in braces and prefixing with the parameter name, like {p = someExpression foo}.
Full example:
import Data.Fin
myNatToFin : (m : Nat) -> (n : Nat) -> { auto p : n `GT` m } -> Fin n
myNatToFin m n = ?x -- See https://stackoverflow.com/questions/29908731/
lteRefl : LTE n n
lteRefl {n = Z} = LTEZero
lteRefl {n = S _} = LTESucc lteRefl
foo : (k : Nat) -> Fin (S k)
foo k = myNatToFin k (S k) {p = LTESucc lteRefl}