Python(超出最大递归深度)vs Haskell(找出答案)

时间:2013-12-05 21:11:22

标签: python haskell recursion

所以我开始学习Haskell了。在得到递归定义之后,我将阶乘定义编码为:

let fac n = if n==0 then 1 else n*fac(n-1)

(完全不同的编码方式,我知道:))

我认为这与python定义相同:

def fac(n): 
  if n==0:
    return 1
  else:
    return n*fac(n-1)

我的问题是关于python引发的最大递归深度错误。尽管2个函数以相同的方式编码,但是当n = 1000时,是什么让python抛出错误并且计算结果?

1 个答案:

答案 0 :(得分:2)

这不是尾递归,所以Haskell最终也会崩溃。

fac :: Int -> Int
fac n = if n == 0 then 1 else n*fac(n-1)

(答案不适合Int,只是让它更快地发生崩溃)

保留正确性问题,只需运行fac 10000000并看到它因堆栈溢出而崩溃。

这是尾递归的:

fac :: Int -> Int
fac n = g 1 n where g a n = if n == 0 then a else g (a*n) (n-1)

不会崩溃。 (但也没有正确的答案,因为使用了Int)

(另外,正如在注释中正确指出的那样,如果我们将函数保留为默认的Integer -> Integer类型,它将使用不受CPU体系结构约束的整数。但从那以后计算将花费更长的时间,我们需要更长的时间才能确保非尾递归最终崩溃。)

在此处的评论中,有ga中有> ghc -O2 -ddump-simpl a.hs > a.dump.lazy ... 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_s11J :: GHC.Prim.Int#) (ww1_s11N :: GHC.Prim.Int#) -> case ww1_s11N of wild_Xn { __DEFAULT -> Main.$wg (GHC.Prim.*# ww_s11J wild_Xn) (GHC.Prim.-# wild_Xn 1); 0 -> ww_s11J } end Rec } 懒惰的投诉。虽然一般来说这是一个问题,但这不是重点,在这种特殊情况下没有区别:

g

现在,同样,但在a 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 } 严格:

g

显然,优化程序可以看到a的唯一返回值是a,因此使{懒惰'{{1}}无效。