I have a function getN'
that is supposed to construct a list of n elements recursively, however I think I'm doing something wrong because I can't index into it and the output looks unexpected:
getN' : (Double -> Double -> Double) -> Double -> Double -> Double -> Int -> List Double
getN' f dt t0 y0 0 = []
getN' f dt t0 y0 n = rk4' :: getN' f dt (t0+dt) rk4' (n-1) where
rk4' = rk4 f dt t0 y0
The output of getN' f 0.1 0 1 100
is:
1.0050062486962987 :: getN' f 0.1 0.1 1.0050062486962987 99 : List Double
Which looks unfamiliar to me. Specifically the syntax head::tail is familiar, but Idris usually prints out the entire result in the REPL, which suggests something isn't right in this instance.
The output of index 0 $ getN' f 0.1 0 1 100
is:
(input):1:9:When checking argument ok to function Prelude.List.index:
Can't find a value of type
InBounds 0 (getN' f 0.1 0.0 1.0 100)
What am I doing/getting wrong?
getN'
isn't total, so the REPL doesn't evaluate the recursive call (as it could loop forever). Set %default total
or total getN' : …
to get a warning from the compiler, or check in the REPL with :total getN'
. Idris can't reason about Int
, and in this particular case, getN' f 0.1 0 1 -1
wouldn't stop.
If you replace Int
with Nat
it works (with 0
to Z
, n
to (S n)
and n - 1
to n
). From another answer: The compiler does only know that subtracting 1 from an Integer
results to an Integer
, but not which number exactly (unlike when doing it with a Nat
). This is because arithmetic with Integer
, Int
, Double
and the various Bits
are defined with primary functions like prim__subBigInt
.
Why index
fails: it needs a proof InBounds k xs
, that the list has at least k
elements. In Haskell, !!
is weaker, and thus can crash at runtime: (getN' f 0.1 0 1 100) !! 101
would compile, but will throw an exception. This can't happen in Idris:
>:t index
Prelude.List.index : (n : Nat) -> (xs : List a) -> {auto ok : InBounds n xs} -> a
>:printdef InBounds
data InBounds : Nat -> List a -> Type where
InFirst : InBounds 0 (x :: xs)
InLater : InBounds k xs -> InBounds (S k) (x :: xs)
auto
means, that the compiler tries to search for a proof ok : InBounds n xs
. But, again, it doesn't evaluate getN' …
, so it doesn't find (or even searches) for a proof. That's the error you are getting: Can't find a value of type InBounds …