伊德里斯真的是 "strictly evaluated?"

Is Idris really "strictly evaluated?"

来自 Haskell,我正在阅读 Idris 关于懒惰(不严格)的故事。我查看了最近的发行说明,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 和 none 从现在到链接的发行说明,请提及任何更改。

解释在这里:http://docs.idris-lang.org/en/latest/faq/faq.html#evaluation-at-the-repl-doesn-t-behave-as-i-expect-what-s-going-on

编译时和运行时间评估语义不同(必然如此,因为在编译时类型检查器需要在存在未知值的情况下评估表达式),并且 REPL 使用编译时概念,这既是为了方便,也是因为在类型检查器中查看表达式如何减少是很有用的。

但是,这里还有一些事情要做。 Idris 发现 myIf 是一个非常小的函数,因此决定将其内联。所以编译时 myFact 实际上有一个看起来有点像的定义:

myFact x = case x == 1 of
                True => 1
                False => x * myFact (x - 1)

所以通常你可以编写像 myIf 这样的控制结构而不用担心制作东西 Lazy,因为 Idris 无论如何都会将它们编译成你想要的控制结构。同样适用于,例如&&|| 以及短路。