通过erlc判断递归函数是否为尾递归

使用erlc编译erlang source code为字节码,通过字节码的特征来判断这个递归是否为尾递归


erlc的相关介绍可以到erlang的文档中找到,这里就不细说。这里主要会使用到的就是 -S 选项。直接上代码

-module(test_file).

-export([test1/1, test2/1, test_case/1]).


test1([Head|Tail]) ->
    test1(Tail);
test1([]) ->
    ok.

test2([Head|Tail]) ->
    test2(Tail),
    ok;
test2([]) ->
    ok.


test_case([Head|Tail]) ->
    case Head of
    	Head when is_integer(Head) ->
    		test_case(Tail);
    	_ ->
    	ok
    end;
test_case([]) ->
    ok.

使用erlc -S生成的字节码

{module, test_file}.  %% version = 0

{exports, [{module_info,0},{module_info,1},{test1,1},{test2,1},{test_case,1}]}.

{attributes, []}.

{labels, 15}.


{function, test1, 1, 2}.
  {label,1}.
    {line,[{location,"e:/GitHub/CODE_T~1/test_file.erl",6}]}.
    {func_info,{atom,test_file},{atom,test1},1}.
  {label,2}.
    {test,is_nonempty_list,{f,3},[{x,0}]}.
    {get_list,{x,0},{x,1},{x,0}}.
    {call_only,1,{f,2}}.
  {label,3}.
    {test,is_nil,{f,1},[{x,0}]}.
    {move,{atom,ok},{x,0}}.
    return.


{function, test2, 1, 5}.
  {label,4}.
    {line,[{location,"e:/GitHub/CODE_T~1/test_file.erl",11}]}.
    {func_info,{atom,test_file},{atom,test2},1}.
  {label,5}.
    {test,is_nonempty_list,{f,6},[{x,0}]}.
    {allocate,0,1}.
    {get_list,{x,0},{x,1},{x,0}}.
    {line,[{location,"e:/GitHub/CODE_T~1/test_file.erl",12}]}.
    {call,1,{f,5}}.
    {move,{atom,ok},{x,0}}.
    {deallocate,0}.
    return.
  {label,6}.
    {test,is_nil,{f,4},[{x,0}]}.
    {move,{atom,ok},{x,0}}.
    return.


{function, test_case, 1, 8}.
  {label,7}.
    {line,[{location,"e:/GitHub/CODE_T~1/test_file.erl",18}]}.
    {func_info,{atom,test_file},{atom,test_case},1}.
  {label,8}.
    {test,is_nonempty_list,{f,10},[{x,0}]}.
    {get_list,{x,0},{x,1},{x,2}}.
    {test,is_integer,{f,9},[{x,1}]}.
    {move,{x,2},{x,0}}.
    {call_only,1,{f,8}}.
  {label,9}.
    {move,{atom,ok},{x,0}}.
    return.
  {label,10}.
    {test,is_nil,{f,7},[{x,0}]}.
    {move,{atom,ok},{x,0}}.
    return.


{function, module_info, 0, 12}.
  {label,11}.
    {line,[]}.
    {func_info,{atom,test_file},{atom,module_info},0}.
  {label,12}.
    {move,{atom,test_file},{x,0}}.
    {line,[]}.
    {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.


{function, module_info, 1, 14}.
  {label,13}.
    {line,[]}.
    {func_info,{atom,test_file},{atom,module_info},1}.
  {label,14}.
    {move,{x,0},{x,1}}.
    {move,{atom,test_file},{x,0}}.
    {line,[]}.
    {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.

由此可见,当函数调用中使用的是一般的call的时候,这个递归就是非尾递归的。是会有堆栈的消耗的。当函数的调用是call_only时,说明就是尾递归的。



Published

23 December 2013

Category

Erlang

Tags



 
comments powered by Disqus