In Haskell we can do the following without getting a runtime error (ref):
mytake 0 _ = []
mytake _ [] = []
mytake n (x:xs) = x : mytake (n-1) xs
print( mytake 0 (undefined::[Int]) )
In Idris, we can do a similar definition, but the behavior is different:
mytake : Integer -> List a -> List a
mytake 0 _ = []
mytake _ [] = []
mytake n (x::xs) = x :: mytake (n-1) xs
printLn( mytake {a = Nat} 0 ?undefined )
In this case we get ABORT: Attempt to evaluate hole Main.undefined. I know Idris is not a lazy language, but my impression was that pattern matching parameters might be separate from the logic for evaluation of data structures (which can be sidestepped in Idris, e.g. with Stream).
In addition to understanding if there is a way around this, I'd also appreciate knowing why Idris behaves in this way.
Well, if I understand right , this could work
module Main
mytake : Integer -> Lazy (List a) -> List a
mytake 0 _ = []
mytake _ [] = []
mytake n (x::xs) = x :: mytake (n-1) xs
main : IO ()
main = printLn (mytake {a = Nat} 0 ?undefined)
But it gives me strange error while compiling
andrey#linux:~/idris> idris -o test test.idr
idris: src/Idris/Core/CaseTree.hs:(645,1)-(654,51): Non-exhaustive patterns in function varRule
Answering to the second part of your question:
This is mostly because of eager evaluation is more predictable. This quesion is in an unofficial FAQ
https://github.com/idris-lang/Idris-dev/wiki/Unofficial-FAQ#why-isnt-idris-lazy
Related
I need some help interpreting an error message regarding implicit arguments in Idris and why a small change fixes it. This is the code:
import Data.Vect
myReverse : Vect n elem -> Vect n elem
myReverse [] = []
myReverse {n} (x :: xs)
= let result = myReverse xs ++ [x] in
?rhs
It results in this error:
When checking left hand side of myReverse:
When checking an application of Main.myReverse:
Type mismatch between
Vect (S len) elem (Type of x :: xs)
and
Vect n elem (Expected type)
Specifically:
Type mismatch between
S len
and
n
However, replacing {n} with {n = S len}, the code type-checks.
I thought that using {n} was simply meant to bring the implicit n argument of the function into scope. Why would this result in an error?
What does the error message mean? The only interpretation I can think of is that the implicit argument n in the type is rewritten due to pattern-matching x::xs into S len, and Idris loses information that these are the same.
How does replacing it with {n = S len} work?
Your best bet in these cases is to use idris to do the programming for you. If you start with
myReverse : Vect n elem -> Vect n elem
myReverse {n} xs = ?myReverse_rhs
and now case split on xs you get
myReverse : Vect n elem -> Vect n elem
myReverse {n = Z} [] = ?myReverse_rhs_1
myReverse {n = (S len)} (x :: xs) = ?myReverse_rhs_2
So not only did idris do a case split on xs, but also on n, since for an empty vector the length must be Z, and for a nonempty vector it must be at least S len. Which also implies that xs is now of length len.
Since n is also on the right hand side of your function, it is obvious that you need to provide something for myReverse_rhs_2 which is of length S len which equals n when you did the pattern matching right.
In the error message idris doesn't know what n is, hence the message.
Let's consider a predicate showing that the elements in the list are in increasing order (and for simplicity let's only deal with non-empty lists):
mutual
data Increasing : List a -> Type where
SingleIncreasing : (x : a) -> Increasing [x]
RecIncreasing : Ord a => (x : a) ->
(rest : Increasing xs) ->
(let prf = increasingIsNonEmpty rest
in x <= head xs = True) ->
Increasing (x :: xs)
%name Increasing xsi, ysi, zsi
increasingIsNonEmpty : Increasing xs -> NonEmpty xs
increasingIsNonEmpty (SingleIncreasing y) = IsNonEmpty
increasingIsNonEmpty (RecIncreasing x rest prf) = IsNonEmpty
Now let's try to write some useful lemmas with this predicate. Let's start with showing that concatenating two increasing lists produces an increasing list, given that the last element of the first list is not greater than the first element of the second list. The type of this lemma would be:
appendIncreasing : Ord a => {xs : List a} ->
(xsi : Increasing xs) ->
(ysi : Increasing ys) ->
{auto leq : let xprf = increasingIsNonEmpty xsi
yprf = increasingIsNonEmpty ysi
in last xs <= head ys = True} ->
Increasing (xs ++ ys)
Let's now try to implement it! A reasonable way seems to be case-splitting on xsi. The base case where xsi is a single element is trivial:
appendIncreasing {leq} (SingleIncreasing x) ysi = RecIncreasing x ysi leq
The other case is more complicated. Given
appendIncreasing {leq} (RecIncreasing x rest prf) ysi = ?wut
it seems reasonable to proceed by recursively proving this for the result of joining rest and ysi by relying on leq and then prepending x using the prf. At this point the leq is actually a proof of last (x :: xs) <= head ys = True, and the recursive call to appendIncreasing would need to have a proof of last xs <= head ys = True. I don't see a good way to directly prove that the former implies the latter, so let's fall back to rewriting and first write a lemma showing that the last element of a list isn't changed by prepending to the front:
lastIsLast : (x : a) -> (xs : List a) -> {auto ok : NonEmpty xs} -> last xs = last (x :: xs)
lastIsLast x' [x] = Refl
lastIsLast x' (x :: y :: xs) = lastIsLast x' (y :: xs)
Now I would expect to be able to write
appendIncreasing {xs = x :: xs} {leq} (RecIncreasing x rest prf) ysi =
let rest' = appendIncreasing {leq = rewrite lastIsLast x xs in leq} rest ysi
in ?wut
but I fail:
When checking right hand side of appendIncreasing with expected type
Increasing ((x :: xs) ++ ys)
When checking argument leq to Sort.appendIncreasing:
rewriting last xs to last (x :: xs) did not change type last xs <= head ys = True
How can I fix this?
And, perhaps, my proof design is suboptimal. Is there a way to express this predicate in a more useful manner?
If rewrite doesn't find the right predicate, try to be explicit with replace.
appendIncreasing {a} {xs = x :: xs} {ys} (RecIncreasing x rest prf) ysi leq =
let rekPrf = replace (sym $ lastIsLast x xs) leq
{P=\T => (T <= (head ys {ok=increasingIsNonEmpty ysi})) = True} in
let rek = appendIncreasing rest ysi rekPrf in
let appPrf = headIsHead xs ys {q = increasingIsNonEmpty rek} in
let extPrf = replace appPrf prf {P=\T => x <= T = True} in
RecIncreasing x rek extPrf
with
headIsHead : (xs : List a) -> (ys : List a) ->
{auto p : NonEmpty xs} -> {auto q : NonEmpty (xs ++ ys)} ->
head xs = head (xs ++ ys)
headIsHead (x :: xs) ys = Refl
Some suggestions:
Use Data.So x instead of x = True, makes run-time functions
easier to write.
Lift Ord a from the constructor to the type, making it
more clear which ordering is used (and you don't have to match on
{a} at appendIncreasing, I guess).
Don't forget that you can
match on variables in constructors, so instead of repeating that Increasing xs has
NonEmpty xs, just use Increasing (x :: xs).
Leading to:
data Increasing : Ord a -> List a -> Type where
SingleIncreasing : (x : a) -> Increasing ord [x]
RecIncreasing : (x : a) -> Increasing ord (y :: ys) ->
So (x <= y) ->
Increasing ord (x :: y :: ys)
appendIncreasing : {ord : Ord a} ->
Increasing ord (x :: xs) -> Increasing ord (y :: ys) ->
So (last (x :: xs) <= y) ->
Increasing ord ((x :: xs) ++ (y :: ys))
Should make proving things a lot easier, especially if you want to include empty lists.
Please consider the following function, even if the implementation is not that relevant:
vectTranspose : Vect n (Fin 3) -> Vect 3 (List (Fin n))
vectTranspose {n = Z} [] = [[],[],[]]
vectTranspose {n = (S len)} (x :: xs) with (natToFin len (S len))
| Just l = let
previous = map (map weaken) (vectTranspose xs)
in updateAt x (l ::) previous
if I try to compute vectTranspose in the REPL, I get [[],[],[]] as expected.
Still, if I add an equality assertion like the following in my code
emptyTest : vectTranspose [] = [[],[],[]]
emptyTest = Refl
then I get a compile error:
When checking right hand side of emptyTest with expected type
vectTranspose [] = [[], [], []]
Type mismatch between
[[], [], []] = [[], [], []] (Type of Refl)
and
vectTranspose [] = [[], [], []] (Expected type)
Specifically:
Type mismatch between
[[], [], []]
and
vectTranspose []
Am I missing something? Should I specify somehow the type of [[],[],[]] in the assertion?
The fact that idris complains about the type of
Specifically:
Type mismatch between
[[], [], []]
and
vectTranspose []
indicates that vectTranspose is still in the type and has not been resolved. That is the case if vectTranspose is not total and indeed it is not:
VecTest.vectTranspose is possibly not total due to:
with block in VecTest.vectTranspose, which is not total as there are missing cases
which happens because you have not covered all the Maybe cases.
A simple solution could be to create a small helper function:
total
natToFin': (n: Nat) -> Fin (S n)
natToFin' Z = FZ
natToFin' (S k) = FS (natToFin' k)
total
vectTranspose : Vect n (Fin 3) -> Vect 3 (List (Fin n))
vectTranspose {n = Z} [] = [[], [], []]
vectTranspose {n = (S len)} (x :: xs) with (natToFin' len)
vectTranspose {n = (S len)} (x :: xs) | l = let
previous = map (map weaken) (vectTranspose xs)
in updateAt x (l ::) previous
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
Given the following Idris code:
import Data.Vect
import Data.Fin
%default total
fins : Vect n (Fin n)
fins {n = Z} = []
fins {n = S n} = FZ :: map FS fins
Permutation : Nat -> Type
Permutation n = {a : Type} -> Vect n a -> Vect n a
permutations : {n : Nat} -> Vect (fact n) (Permutation n)
permutations {n = Z} = [id]
permutations {n = S n} =
rewrite multCommutative (S n) (fact n) in
concat $ map inserts (permutations {n = n})
where
inserts : Permutation k -> Vect (S k) (Permutation (S k))
inserts pi = map (\i => \(x :: xs) => insertAt i x . pi $ xs) fins
I am getting the following error message from Idris 0.9.16 (and no further details):
Type checking .\Permutations.idr
Permutations.idr:15:14:Universe inconsistency
However, by changing it just so slightly, so that the second clause of permutations becomes
permutations {n = S n} =
rewrite multCommutative (S n) (fact n) in
concat . map inserts $ permutations {n = n}
then it suddenly typechecks.
Is there some special magic going on inside Idris perhaps in the handling of ($) and (.), similar to what GHC does so that they work in the presence of higher-rank types?
As of Idris 0.10.2, my original code (using concat $ map inserts (permutations {n = n}) in the definition of permutations) typechecks without hiccup.