Erlang:检查重复插入的元素

时间:2016-03-12 14:20:48

标签: erlang erl

我想知道插入的元素是否重复。

以下是我正在寻找的简单示例:

在第一次运行中应该返回false。

check_duplicate("user", "hi").

但是在第二轮中应该返回true。

check_duplicate("user", "hi").

1 个答案:

答案 0 :(得分:3)

函数式编程的最佳特性之一是纯函数。甚至有像Haskell这样的函数式语言,你可以编写一个不纯的函数。纯函数始终为同一参数返回相同的值。不纯函数有副作用,可以为同一个参数返回不同的结果。这意味着必须改变一些你不能看作函数参数的状态。你只是要求它。 Erlang允许你这样做。你有很多选择如何做到这一点。最干净的是发送消息并从另一个进程接收消息。 (无论如何它都是不纯的,但在Erlang中却是惯用的。下面的代码非常简单,不适合生产使用。你应该使用OTP行为和设计原则。)

has_dupes(Jid, Text) ->
    Ref = make_ref(),
    seen ! {Ref, self(), {Jid, Text}},
    receive {Ref, Result} -> Result end.

start_seen() ->
    spawn(fun()-> register(seen, self()), loop_seen([]) end).

loop_seen(Seen) ->
    receive {Ref, From, Term} ->
        case lists:member(Term, Seen) of
            true  ->
                From ! {Ref, true},
                loop_seen(Seen);
            false ->
                From ! {Ref, false},
                loop_seen([Term|Seen])
        end
    end.

另一种是存储和读取ets(Erlang Term Storage)。

has_dupes(Jid, Text) ->
    (catch ets:new(seen, [set, named_table])),
    not ets:insert_new(seen, {{Jid, Text}}).

但有一个问题。该表由进程拥有,并在进程终止时被删除。它的名字是全球性的等等。另一个更脏的是存储和读取流程字典中的值。

has_dupes(Jid, Text) ->
    case get({Jid, Text}) of
        undefined ->
            put({Jid, Text}, seen),
            false;
        seen ->
            true
    end.

但这很糟糕,你几乎不应该使用这样的代码。在大多数情况下,您应该使用显式状态

new_seen() -> [].

has_dupes(Jid, Text, Seen) ->
    Term = {Jid, Text},
    case lists:member(Term, Seen) of
        true  -> {true, Seen};
        false -> {false, [Term|Seen]}
    end.

这是最佳时间的最佳解决方案,因为它是一个纯粹的功能。当您需要观看更多条款时,您可以使用更好的数据结构,例如setsmaps,以获得更好的效果。