fac :: Int -> Int
fac n = g 1 n where
g !a n = if n == 0 then a else g (a*n) (n-1)
> ghc -O2 -XBangPatterns -ddump-simpl a.hs > a.dump.eager
...
Rec {
Main.$wg [Occ=LoopBreaker]
:: GHC.Prim.Int# -> GHC.Prim.Int# -> GHC.Prim.Int#
[GblId, Arity=2, Caf=NoCafRefs, Str=DmdType LL]
Main.$wg =
\ (ww_s11P :: GHC.Prim.Int#) (ww1_s11T :: GHC.Prim.Int#) ->
case ww1_s11T of wild_Xs {
__DEFAULT ->
Main.$wg (GHC.Prim.*# ww_s11P wild_Xs) (GHC.Prim.-# wild_Xs 1);
0 -> ww_s11P
}
end Rec }
这不是尾部递归,所以Haskell最终也会崩溃。在
(答案不适合Int,只是让它更快地发布崩溃)
不考虑正确性问题,只需运行
fac 10000000
并看到它因堆栈溢出而崩溃。在下面是尾部递归:
^{pr2}$不会崩溃。(但也不是正确答案,因为使用了Int)
(另外,正如注释中正确指出的那样,如果我们让函数保留默认的
Integer -> Integer
类型,它将使用不受CPU体系结构约束的整数。但从那时起,计算将花费更长的时间,我们将需要更长的时间来满足我们自己,即非尾部递归最终会崩溃。)在这里的评论中有人抱怨
g
在a
中懒惰。一般来说,这是一个问题,但这并不是重点,在这个特殊情况下,没有区别:现在,同样,但是要使
g
严格在a
中:显然,优化器可以看到
g
的唯一返回值是a
,因此使其变懒是a
没有任何好处。在相关问题 更多 >
编程相关推荐