来自哈斯克尔,我正在阅读有关伊德里斯关于懒惰(非严格)的故事。我推测了最近的发行说明,found code类似于以下
myIf : (b : Bool) -> (t : Lazy a) -> (e : Lazy a) -> a
myIf True t e = t
myIf False t e = e
我写了一个简单的阶乘函数来测试它
myFact : Int -> Int
myFact n = myIf (n == 1) 1 (n * myFact (n-1))
我跑了它,它运作了!
> myFact 5
120 : Int
我决定通过将myIf
的类型签名更改为
myIf : (b : Bool) -> a -> a -> a
我重新加载了idris
repl,并再次运行myFact 5
期望无限递归。令我惊讶的是,它仍然以同样的方式运作!
idris能否在何时避免严格?为什么这不能永远地归还?
我正在使用Idris 0.9.15,现在和链接的笔记之间没有发行说明,请提及任何更改。
答案 0 :(得分:17)
编译时和运行时评估语义是不同的(必须如此,因为在编译时类型检查器需要在存在未知值的情况下计算表达式),并且REPL使用编译时概念,既方便又因为查看类型检查器中表达式的减少方式很有用。
但是,这里还有更多。伊德里斯发现myIf
是一个非常小的功能,并决定内联它。所以当编译时myFact
实际上有一个看起来有点像的定义:
myFact x = case x == 1 of
True => 1
False => x * myFact (x - 1)
所以通常你可以编写像myIf
这样的控制结构,而不用担心制作Lazy
,因为Idris会将它们编译成你想要的控制结构。同样如下,例如&&
和||
以及短路。