Erlang代码批判

dag*_*da1 3 erlang

我试图了解一些基本的erlang功能,我可以对以下内容进行一些评论.

我有以下erlang代码,它接受一个元组列表,如果找到一个键,则返回一个减去元素的列表:

delete(Key, Database) ->
    remove(Database, Key, []).

remove([], Key, Acc) ->
    Acc;
remove([H|T], Key, Acc) ->
    if
        element(1, H) /= Key ->             
            [H| remove(T, Key, Acc)];
        true  -> 
            remove(T, Key, Acc)
    end.
Run Code Online (Sandbox Code Playgroud)

这是一个很好的方法吗?

if语句似乎不正确.

也是我使用累加器Acc使这个尾递归?

Hyn*_*dil 5

不,你的使用Acc不会使它尾递归.if返回的分支[H| remove(T, Key, Acc)]不是尾调用,大部分时间都会使用此分支.更准确地说,你的使用Acc是无用的,因为它是[]全时的,你根本不会改变它的价值.正确的代码应该是这样的.

delete(Key, Database) ->
    remove(Database, Key, []).

remove([], Key, Acc) ->
    lists:reverse(Acc);
remove([H|T], Key, Acc) ->
    if
        element(1, H) /= Key ->             
            remove(T, Key, [H|Acc]);
        true  -> 
            remove(T, Key, Acc)
    end.
Run Code Online (Sandbox Code Playgroud)

但如果您的列表成员总是成对,我宁愿直接模式匹配:

delete(Key, Database) ->
    remove(Database, Key, []).

remove([], Key, Acc) ->
    lists:reverse(Acc);
remove([{Key, _}|T], Key, Acc) ->
    remove(T, Key, Acc);
% if it should delete only first occurrence then lists:reverse(Acc, T);
remove([H|T], Key, Acc) ->
    remove(T, Key, [H|Acc]).
Run Code Online (Sandbox Code Playgroud)

但我认为这是可以应用神话的例子:尾递归函数比递归函数快得多,所以我会使用更简单的递归版本:

delete(Key, []) -> [];
delete(Key, [{Key, _}|T]) -> delete(Key, T);
% if it should delete only first occurrence then just T;
delete(Key, [H|T]) -> [H | delete(Key, T)].
Run Code Online (Sandbox Code Playgroud)