我有一个函数getN'
,它应该递归地构造一个n个元素的列表,但是我认为我做错了,因为我无法索引它并且输出看起来很意外:
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
getN' f 0.1 0 1 100
的输出是:
1.0050062486962987 :: getN' f 0.1 0.1 1.0050062486962987 99 : List Double
对我来说这看起来很陌生。具体来说,语法head :: tail很熟悉,但Idris通常会在REPL中打印出整个结果,这表明在这种情况下有些不对。
index 0 $ getN' f 0.1 0 1 100
的输出是:
(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)
我在做什么/出错?
答案 0 :(得分:1)
getN'
不是完全的,因此REPL不会评估递归调用(因为它可以永远循环)。设置%default total
或total getN' : …
以获取编译器的警告,或使用:total getN'
检入REPL。 Idris无法推理Int
,在这种特殊情况下,getN' f 0.1 0 1 -1
不会停止。
如果您将Int
替换为Nat
,则0
替换为Z
,n
改为(S n)
和n - 1
到n
)。来自another answer:编译器只知道从Integer
结果中减去1到Integer
,但不是从哪个数字中减去(与使用Nat
时不同)。这是因为使用Integer
等主要函数定义了Int
,Double
,Bits
和各种prim__subBigInt
的算术。
为什么index
失败:它需要一个证明InBounds k xs
,该列表至少包含k
个元素。在Haskell中,!!
较弱,因此可能在运行时崩溃:(getN' f 0.1 0 1 100) !! 101
将编译,但会抛出异常。这在伊德里斯不可能发生:
>: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
表示编译器尝试搜索证明ok : InBounds n xs
。但是,它再次没有评估getN' …
,因此它没有找到(甚至搜索)证据。这是你得到的错误:Can't find a value of type InBounds …