如何在Idris交互中评估此递归函数?

时间:2017-05-19 20:58:31

标签: haskell recursion idris

涉足伊德里斯,我试图将this Haskell function移到伊德里斯。我想我用这段代码成功了......

windowl : Nat -> List a -> List (List a)
windowl size = loop
  where
    loop xs = case List.splitAt size xs of
      (ys, []) => if length ys == size then [ys] else []
      (ys, _) => ys :: loop (drop 1 xs)

但是,当我在交互式idris中调用它时,似乎只评估了对函数的第一次调用,递归的下一步不是。这是我在控制台上得到的。

*hello> windowl 2 [1,2,3,4,5]
[1, 2] :: Main.windowl, loop Integer 2 [2, 3, 4, 5] : List (List Integer)

有人可以告诉我发生了什么以及如何完全评估这个功能吗?

1 个答案:

答案 0 :(得分:4)

正如manual

中所述
  

在编译时,它[Idris]只会评估它知道的全部内容   ...... [跳过] ......   为方便起见,REPL使用编译时的评估概念。

整体检查程序无法发现windowl函数实际上是总数,因此我们可以使用assert_smaller construction作弊:

total
windowl : Nat -> List a -> List (List a)
windowl size = loop
  where
    loop : List a -> List (List a)
    loop xs = case List.splitAt size xs of
      (ys, []) => if length ys == size then [ys] else []
      (ys, _) => ys :: loop (assert_smaller xs $ drop 1 xs)

或更改loop以使整体检查器显而易见:

total
windowl : Nat -> List a -> List (List a)
windowl size = loop
  where
    loop : List a -> List (List a)
    loop [] = []
    loop xs@(x :: xs') = case List.splitAt size xs of
      (ys, []) => if length ys == size then [ys] else []
      (ys, _) => ys :: loop xs'

是的,我在这里偷工减料,用模式匹配替换硬编码的drop 1来说明这个想法。更一般的情况可能需要更多的工作。

此时,REPL完全评估表达式:

λΠ> windowl 2 [1,2,3,4,5]
[[1, 2], [2, 3], [3, 4], [4, 5]] : List (List Integer)