我有以下计划:
my_sum 0 = 54321
my_sum i = i + (my_sum (i - 1))
main = do
print $ my_sum 12345
我想知道生成的my_sum
函数是否是递归的。换句话说,haskell会将此变换为非递归类型。
我试图看到本机c--代码(asm几乎相同)。但这对我来说太难了。代码为my_sum
:
my_sum_s24N_entry() // [R1]
{ info_tbl: [(c25x,
label: block_c25x_info
rep:StackRep [False, False]),
(c267,
label: my_sum_s24N_info
rep:HeapRep 1 nonptrs { Fun {arity: 1 fun_type: ArgSpec 5} })]
stack_info: arg_space: 8 updfr_space: Just 4
}
{offset
c267:
_s24N::P32 = R1;
_s24O::P32 = P32[Sp];
if ((Sp + 8) - 32 < SpLim) goto c268; else goto c269;
c269:
Hp = Hp + 8;
if (Hp > HpLim) goto c26b; else goto c26a;
c26b:
HpAlloc = 8;
goto c268;
c268:
R1 = _s24N::P32;
call (stg_gc_fun)(R1) args: 8, res: 0, upd: 4;
c26a:
I32[Hp - 4] = sat_s24V_info;
_c25n::P32 = Hp - 4;
I32[Sp - 8] = c25x;
P32[Sp - 24] = GHC.Integer.Type.$fEqInteger_closure;
I32[Sp - 20] = stg_ap_pp_info;
P32[Sp - 16] = _s24O::P32;
P32[Sp - 12] = _c25n::P32;
P32[Sp - 4] = _s24N::P32;
Sp = Sp - 24;
call GHC.Classes.==_info() returns to c25x, args: 20, res: 4, upd: 4;
c25x:
_s24N::P32 = P32[Sp + 4];
_s24O::P32 = P32[Sp + 8];
_s24W::P32 = R1;
_c266::P32 = _s24W::P32 & 3;
if (_c266::P32 != 1) goto c265; else goto c264;
c265:
Hp = Hp + 8;
if (Hp > HpLim) goto c26j; else goto c26i;
c26j:
HpAlloc = 8;
R1 = _s24W::P32;
call stg_gc_unpt_r1(R1) returns to c25x, args: 4, res: 4, upd: 4;
c26i:
I32[Hp - 4] = GHC.Integer.Type.S#_con_info;
I32[Hp] = 54321;
_c26k::P32 = Hp - 3;
P32[Sp] = GHC.Num.$fNumInteger_closure;
I32[Sp + 4] = stg_ap_p_info;
P32[Sp + 8] = _c26k::P32;
call GHC.Num.fromInteger_info() args: 16, res: 0, upd: 4;
c264:
Hp = Hp + 16;
if (Hp > HpLim) goto c26e; else goto c26d;
c26e:
HpAlloc = 16;
R1 = _s24W::P32;
call stg_gc_unpt_r1(R1) returns to c25x, args: 4, res: 4, upd: 4;
c26d:
I32[Hp - 12] = sat_s250_info;
P32[Hp - 4] = _s24N::P32;
P32[Hp] = _s24O::P32;
_c25B::P32 = Hp - 12;
P32[Sp - 4] = GHC.Num.$fNumInteger_closure;
I32[Sp] = stg_ap_pp_info;
P32[Sp + 4] = _s24O::P32;
P32[Sp + 8] = _c25B::P32;
Sp = Sp - 4;
call GHC.Num.+_info() args: 20, res: 0, upd: 4;
}
}
答案 0 :(得分:3)
答案是否定的,GHC不会将此优化为尾递归函数。正如评论者所说,要看到这一点,你应该看看GHC核心^:
Rec {
my_sum :: Integer -> Integer
my_sum =
\ (ds :: Integer) ->
case eqInteger# ds my_sum'2 of wild { __DEFAULT ->
case tagToEnum# wild of _ {
False -> plusInteger ds (my_sum (minusInteger ds lvl));
True -> my_sum'1
}
}
end Rec }
这个函数显然不是尾递归的 - 最外面的调用是plusInteger
。 GHC核心是执行所有优化后的代码 - 此代码实际上是转换为机器代码的代码。所以你知道你的函数在核心中是不是尾递归的,它实际上不是尾递归的。它本质上只是Haskell,除了一些有趣的名字,所以阅读它不应该是一个问题。
如果你想要一个尾递归函数,只需使用foldl'
:
import Data.List (foldl')
my_sum' :: Integer -> Integer
my_sum' i0 = foldl' (+) 54321 [0..i0]
其中给出了以下核心:
my_sum' :: Integer -> Integer
my_sum' =
\ (i0 :: Integer) ->
letrec {
go :: Integer -> Integer -> Integer
go =
\ (x :: Integer) (eta :: Integer) ->
case gtInteger# x i0 of wild { __DEFAULT ->
case tagToEnum# wild of _ {
False -> go (plusInteger x $fEnumInteger1) (plusInteger eta x);
True -> eta
}
}; } in
go my_sum'2 my_sum'1
此处my_sum'2
,my_sum'1
和lvl
是该计划中的常量:
my_sum'2 :: Integer
my_sum'2 = 0
my_sum'1 :: Integer
my_sum'1 = 54321
lvl :: Integer
lvl = 1
^使用选项-ddump-simpl -dsuppress-idinfo -dsuppress-coercions -dsuppress-type-applications -dsuppress-uniques -dsuppress-module-prefixes --make
生成