Erlang的尾递归

时间:2010-04-17 14:14:26

标签: erlang

我真的很难理解Erlang中的尾递归。

我有以下eunit测试:

db_write_many_test() ->
    Db = db:new(),
    Db1 = db:write(francesco, london, Db),
    Db2 = db:write(lelle, stockholm, Db1),
    ?assertEqual([{lelle, stockholm},{francesco, london}], Db2).

这是我的实施:

-module(db) .
-include_lib("eunit/include/eunit.hrl").
-export([new/0,write/3]).

new() ->
    [].

write(Key, Value, Database) ->
    Record = {Key, Value},
    [Record|append(Database)].

append([H|T]) ->
    [H|append(T)];  
append([])  ->
    [].

我的实现是否递归,如果没有,我怎么能这样做呢?

提前致谢

1 个答案:

答案 0 :(得分:2)

你的实现不是尾递归的,因为append必须在计算尾部时保持在列表的头部。为了使函数成为尾递归,返回值不能依赖于函数调用返回的值以外的值。

你可以像这样重写它:

append(Acc, []) -> %% termination;
    Acc;
append(Acc, [H|T]) ->
    Acc2 = Acc ++ dosomethingto(H); %% maybe you meant this to be your write function?
    append(Acc2, T); %% tail rercursive

请注意,一旦发生尾递归调用,所有工作都已完成。因此,append函数可以忘记函数体中的,只需要记住它传递给下一次调用的参数的值。

另请注意,我在recursive子句之前放置了terminate子句。 Erlang按顺序评估子句,因为终止子句通常更具体,不太具体的递归子句会隐藏它们,从而阻止函数返回,这最不像你想要的行为。