阅读和播放伊德里斯官方教程中的一些例子让我对懒惰的评价感到有些困惑。
正如教程中所述,Idris使用了急切的评估,然后他们继续给出一个不合适的例子
ifThenElse : Bool -> a -> a -> a
ifThenElse True t e = t
ifThenElse False t e = e
然后他们继续使用延迟评估显示一个例子
ifThenElse : Bool -> Lazy a -> Lazy a -> a
ifThenElse True t e = t
ifThenElse False t e = e
我喜欢在阅读时尝试一下,所以我创建了一个低效的Fibonacci函数来测试非懒惰和懒惰的ifThenElse
。
fibo : Nat -> Nat
fibo Z = Z
fibo (S Z) = S Z
fibo (S(S Z)) = S(S Z)
fibo (S(S(S n))) = fibo (S(S n)) + fibo (S n)
-- the non lazy
ifThenElse1 : Bool -> (t: a) -> (f: a) -> a
ifThenElse1 False t f = f
ifThenElse1 True t f = t
-- should be slow when applied to True
iftest1 : Bool -> Nat
iftest1 b = ifThenElse1 b (fibo 5) (fibo 25)
-- the lazy
ifThenElse2 : Bool -> (t: Lazy a) -> (f: Lazy a) -> a
ifThenElse2 False t f = f
ifThenElse2 True t f = t
-- should be fast when applied to True
iftest2 : Bool -> Nat
iftest2 b = ifThenElse2 b (fibo 5) (fibo 25)
鉴于Idris应该进行急切的评估,我认为即使应用于True,iftest1
的执行速度也会因(fibo 25)
而减慢。但是,iftest1
和iftest2
在应用于True时执行速度非常快。也许我对懒惰/渴望的理解从根本上是有缺陷的?
观察伊德里斯的懒惰和渴望之间的区别有什么好的例子?
答案 0 :(得分:2)
您可能尝试过Idris REPL中的iftest1
和iftest2
。 The REPL uses different evaluation order than compiled code:
作为一种完全依赖类型的语言,Idris有两个阶段来评估事物,编译时和运行时。在编译时,它只会评估它知道的全部内容(即终止并覆盖所有可能的输入),以便保持类型检查的可判定性。编译时评估器是Idris内核的一部分,并使用HOAS(高阶抽象语法)样式的值表示在Haskell中实现。由于此处已知所有内容都具有正常形式,因此评估策略实际上并不重要,因为它将获得相同的答案,并且在实践中它将执行Haskell运行时系统选择的任何操作。
为方便起见,REPL使用编译时的评估概念。