Erlang代码评论

Erlang代码评论,erlang,Erlang,我试图了解一些基本的erlang功能,我可以对以下内容发表一些评论 我有以下erlang代码,它获取元组列表,并在找到键时返回一个减去元素的列表: delete(Key, Database) -> remove(Database, Key, []). remove([], Key, Acc) -> Acc; remove([H|T], Key, Acc) -> if element(1, H) /= Key ->

我试图了解一些基本的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.
这是一个很好的方法吗

if语句似乎不正确


我对累加器Acc的使用是否使尾部递归?

不,您对
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.
但如果您的列表成员总是成对的,我更喜欢直接模式匹配:

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]).
但我认为这是一个可以应用的示例,因此我将使用更简单的递归版本:

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)].

如前所述,有一个标准模块函数已经实现了这一点(PropList:delete)。不需要多说,但是

我倾向于保留原始的方法名(delete),但有一个本地版本,包括作为参数的累加器。上下文让我觉得“数据库”中元组的顺序无关紧要,因此不需要使用list:reverse

-module(foo).
-export([delete/2]).

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

delete(_Key, [], Acc) ->
    Acc;
delete(Key, [{Key, _} | T], Acc) ->
    delete(Key, T, Acc);
delete(Key, [Entry={_, _} | T], Acc) ->
    delete(Key, T, [Entry | Acc]).
这里有几件事:

  • 尾部递归;一般来说,我认为使用尾部递归更安全——虽然对主体递归调用进行了优化,但您确实需要使用实际(应用程序)数据进行一些性能度量,以进行比较
  • 请注意,我们这里不接受任何旧的列表;delete/3中的条目模式匹配有助于确保这一点(取决于它的用途,您可能需要也可能不需要)

如果您想知道某些内容是否是尾部递归的,请考虑在函数返回之前是否有任何内容需要调用的返回值。在这种情况下,反对者正在等待结果,所以不,这不是尾部递归。这是对我在这里为你回答的问题的重新表述:@Jeremy这不是一个完全的重新表述,因为我正在寻找关于if语句的指导,但我接受了这一点,不会再就这个主题发表文章。有趣的是,在这个问题上没有重要的顺序“数据库”所以没有
列表的尾部递归版本:反向
应该是最快的解决方案。