1

I want to know if inserted elements are duplicated.

Here is simple example for what I'm looking for :

In first run should return false.

check_duplicate("user", "hi").

But in second run should return true.

check_duplicate("user", "hi").
Mr. zero
  • 245
  • 4
  • 18
  • 1
    Your question doesn't make sense to me. Are your examples correct? – Peer Stritzinger Mar 12 '16 at 17:35
  • @PeerStritzinger Hi, I don't know alot of Erlang. but my question on how to catch duplicated inserted elements to the function. like if I run this function check_duplicate("user", "hi") Twice with the same inserted elements ("user", "hi") it should return True. thnx. – Mr. zero Mar 12 '16 at 17:41
  • @Mr.zero, insert elements to sets. And check by function http://erlang.org/doc/man/sets.html#is_element-2 –  Mar 12 '16 at 17:58
  • @Atomic_alarm Hi, Can u make simple example please. I don't know alot of Erlang. thnx. – Mr. zero Mar 12 '16 at 18:17
  • no, it's just advice. I also don't understand what you specifically you need. –  Mar 12 '16 at 18:42

1 Answers1

3

One of best features of functional programming is pure functions. There are even functional languages like Haskell where you can't write an impure function. A pure function always returns the same value for the same argument. An impure function has side effect and can return different result for the same argument. It means there has to change some state which you can't see as an argument to the function. You are asking just for it. Erlang allows you to do it. You have many options how to do it. The cleanest is to send a message and receive a message from another process. (It's impure anyway, but idiomatic in Erlang. The following code is very simple and not ready for production use. You should use OTP behaviours and design principles for it.)

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.

The other is to store and read from ets (Erlang Term Storage).

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

But there is a catch. The table is owned by the process and is deleted when the process dies. Its name is global and so on. Another one and much more dirty is to store and read a value from process dictionary.

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

But it is nasty and you should almost never use code like this. In most cases you should use explicit state

new_seen() -> [].

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

It is most time best solution because it is a pure function. You can use better data structures like sets and maps for better performance when you need to watch a bigger amount of terms.

Hynek -Pichi- Vychodil
  • 26,174
  • 5
  • 52
  • 73
  • sorry for late I know my question on ur answer is late (sorry again). but in last example has_dupes(Jid, Text, Seen) ->. What should be Seen here ? many thanks. – Mr. zero Mar 29 '16 at 18:12
  • @Mr.zero: `Seen` is a state, it's list in this example, but could be a map, set, ... I have added constructor function to my answer. – Hynek -Pichi- Vychodil Mar 30 '16 at 02:07