无法索引到由递归函数构造的列表

时间:2018-04-15 11:30:05

标签: list recursion functional-programming idris

我有一个函数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)

我在做什么/出错?

1 个答案:

答案 0 :(得分:1)

getN'不是完全的,因此REPL不会评估递归调用(因为它可以永远循环)。设置%default totaltotal getN' : …以获取编译器的警告,或使用:total getN'检入REPL。 Idris无法推理Int,在这种特殊情况下,getN' f 0.1 0 1 -1不会停止。

如果您将Int替换为Nat,则0替换为Zn改为(S n)n - 1n)。来自another answer:编译器只知道从Integer结果中减去1到Integer,但不是从哪个数字中减去(与使用Nat时不同)。这是因为使用Integer等主要函数定义了IntDoubleBits和各种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 …