简体   繁体   English

Haskell可以优化不尾递归功能吗?

[英]Can haskell optimise not tail recursive function?

I have following program: 我有以下程序:

my_sum 0 = 54321
my_sum i = i + (my_sum (i - 1))

main = do
    print $ my_sum 12345

I want to find out whether generated my_sum function is recursive. 我想找出生成的my_sum函数是否是递归的。 In other words, will haskell transform this one to not recursive kind. 换句话说,将haskell转换为一种非递归类型。

I am tried to see native c-- code (asm almost the same). 我尝试查看本机c代码(asm几乎相同)。 But it is too difficult for me. 但这对我来说太困难了。 It is code of my_sum : 它是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;
 }
 } 

The answer is no, GHC will not optimize this to a tail recursive function. 答案是否定的,GHC不会将其优化为尾递归函数。 As a commenter suggests, to see this, you should look at the GHC core^: 正如评论者所建议的那样,要查看此内容,您应该查看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 }

This function is clearly not tail-recursive - the outermost call is to plusInteger . 该函数显然不是尾递归的-最外层的调用是plusInteger The GHC core is the code after all optimizations are performed - this code is what is actually translated to machine code. GHC核心是执行所有优化后的代码-该代码实际上是转换为机器代码的代码。 So you know if your function is not tail-recursive in core, it really isn't tail recursive. 因此,您知道函数在内核中是否不是尾部递归,那么它实际上不是尾部递归。 It is also essentially just Haskell, aside from some funny names, so reading it should not be a problem. 除了一些有趣的名称之外,它实际上基本上也只是Haskell,因此阅读它应该不是问题。

If you want a tail recursive function, just use foldl' : 如果您想要一个尾部递归函数,只需使用foldl'

import Data.List (foldl')

my_sum' :: Integer -> Integer 
my_sum' i0 = foldl' (+) 54321 [0..i0]

Which gives the following core: 它给出了以下核心:

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

Here my_sum'2 , my_sum'1 and lvl are the constants in the program: 这里my_sum'2my_sum'1lvl是程序中的常量:

my_sum'2 :: Integer
my_sum'2 = 0
my_sum'1 :: Integer
my_sum'1 = 54321
lvl :: Integer
lvl = 1

^ Generated with the options -ddump-simpl -dsuppress-idinfo -dsuppress-coercions -dsuppress-type-applications -dsuppress-uniques -dsuppress-module-prefixes --make ^使用选项-ddump-simpl -dsuppress-idinfo -dsuppress-coercions -dsuppress-type-applications -dsuppress-uniques -dsuppress-module-prefixes --make

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM