在Haskell中,我可能会这样实现if语句:
在Racket中,我可以像这样实现一个有缺陷的
在Idris中,我可以这样实现
我原以为Idris会像Racket一样对两个参数都进行求值,但事实并非如此!
Idris是如何决定何时对事物进行求值的?
if
。if' True x y = x
if' False x y = y
spin 0 = ()
spin n = spin (n - 1)
这个表现符合我的预期:
haskell> if' True (spin 1000000) () -- takes a moment
haskell> if' False (spin 1000000) () -- immediate
在Racket中,我可以像这样实现一个有缺陷的
if
:(define (if2 cond x y) (if cond x y))
(define (spin n) (if (= n 0) (void) (spin (- n 1))))
这个 表现符合我的预期:
racket> (if2 #t (spin 100000000) (void)) -- takes a moment
racket> (if2 #f (spin 100000000) (void)) -- takes a moment
在Idris中,我可以这样实现
if
:if' : Bool -> a -> a -> a
if' True x y = x
if' False x y = y
spin : Nat -> ()
spin Z = ()
spin (S n) = spin n
这个行为让我感到惊讶:
idris> if' True (spin 1000) () -- takes a moment
idris> if' False (spin 1000) () -- immediate
我原以为Idris会像Racket一样对两个参数都进行求值,但事实并非如此!
Idris是如何决定何时对事物进行求值的?
spin : Nat -> ()
更改为spin : Nat -> Bool
(我猜想 Idris 意识到()
只有一个 inhabitant 并优化了对spin
的调用),但在那之后,无论进入if
的哪个分支,可执行文件都需要一段时间才能运行。 - Snowballspin 1000
是终止的且没有副作用,这个表达式也不会在编译时被计算并在生成的代码中被其结果替换,以便两个版本的if
行在运行时立即返回它们的结果呢?(Snowballs上面的评论表明它并没有这样做。) - Lii