我正在尝试理解一些基本的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会使这个尾部递归吗?
发布于 2010-04-18 06:35:51
不,您使用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]).但我认为这是一个可以应用Myth: Tail-recursive functions are MUCH faster than recursive functions的例子,所以我会使用更简单的递归版本:
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)].发布于 2010-04-19 00:13:33
如前所述,已经有一个标准的模块函数可以做到这一点(proplists:delete)。不需要多说,但是...
我倾向于保留原来的方法名(delete),但有一个包含累加器作为参数的本地版本。上下文让我认为元组在“数据库”中的顺序并不重要,因此列表: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]).这里有几件事:
https://stackoverflow.com/questions/2659915
复制相似问题