简体   繁体   中英

Function clause error Erlang

I am trying to understand process communication in erlang. Here I have a master process and five friends process. If a friend sends a message to any of the other 5 they have to reply back. But the master should be aware of all this. I am pasting the code below.

-module(prog).
-import(lists,[append/2,concat/1]).

-import(maps,[from_lists/1,find/2,get/2,update/3]).
-import(string,[equal/2]).
-import(file,[consult/1]).
-export([create_process/1,friends/4, master/1, main/0,prnt/1]).     



%% CREATE PROCESS 
create_process([])->ok;
create_process([H|T])->
    {A,B} = H,
    Pid = spawn(prog,friends,[B,self(),0,A]),
    register(A,Pid),
    create_process(T).


%% FRIENDS PROCESS
friends(Msg, M_pid, State, Self_name)->
    S = lists:concat([Self_name," state =",State,"\n"]),
    io:fwrite(S),
    if
        State == 0 ->
            timer:sleep(500),
            io:fwrite("~p~n",[Self_name]),
            lists:foreach(fun(X) -> whereis(X)!{Self_name,"intro",self()} end, Msg),
            friends(Msg, M_pid, State + 1, Self_name);
        State > 0 ->
            receive
                {Process_name, Process_msg, Process_id} -> 
                    I = equal(Process_msg,"intro"),
                    R = equal(Process_msg,"reply"),
                    XxX = lists:concat([Self_name," recieved ",Process_msg," from ",Process_name,"\n"]),
                    io:fwrite(XxX),
                    if
                        I == true ->
                            io:fwrite("~p~n",[whereis(Process_name)]),
                            M_pid!{lists:concat([Self_name," received intro message from ", Process_name , "[",Process_id,"]"]), self()},
                            io:fwrite(I),
                            whereis(Process_name)!{Self_name, "reply",self()},

                            friends(Msg, M_pid, State + 1, Self_name);
                        R == true ->
                            M_pid!{lists:concat([Self_name," received reply message from ", Process_name , "[",Process_id,"]"]), self()},
                            io:fwrite(R),
                            friends(Msg, M_pid, State + 1, Self_name)
                    end
            after
                1000->
                    io:fwrite(lists:concat([Self_name," has received no calls for 1 second, ending..."]))
            end

    end.


master(State)->
    receive
        {Process_message, Process_id} ->
            io:fwrite(Process_message),
            master(State+1)
    after
        2000->
            ok
    end.


main() ->
    B = [{john, [jill,joe,bob]},
{jill, [bob,joe,bob]},
{sue, [jill,jill,jill,bob,jill]},
{bob, [john]},
{joe, [sue]}],
    create_process(B),
    io:fwrite("~p~n",[whereis(sue)]),

    master(0).

I think the line in friends() function,

M_pid!{lists:concat([Self_name," received intro message from ", Process_name , "[",Process_id,"]"]), self()}

is the cause of error but I cannot understand why. M_pid is known and I am concatenating all the info and sending it to master but I am confused why it isnt working.

The error I am getting is as follows:

Error in process <0.55.0> with exit value: {function_clause,[{lists,thing_to_list,
                         [<0.54.0>],
                         [{file,"lists.erl"},{line,603}]},
                  {lists,flatmap,2,[{file,"lists.erl"},{line,1250}]},
                  {lists,flatmap,2,[{file,"lists.erl"},{line,1250}]},
                  {prog,friends,4,[{file,"prog.erl"},{line,45}]}]}

I dont know what is causing the error. Sorry for asking noob questions and thanks for your help.

An example of what Dogbert discovered:

-module(my).
-compile(export_all).

go() ->
    Pid = spawn(my, nothing, []),
    lists:concat(["hello", Pid]).


nothing() -> nothing.

In the shell:

2> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}

3> my:go().
** exception error: no function clause matching 
                    lists:thing_to_list(<0.75.0>) (lists.erl, line 603)
     in function  lists:flatmap/2 (lists.erl, line 1250)
     in call from lists:flatmap/2 (lists.erl, line 1250)
4> 

But:

-module(my).
-compile(export_all).

go() ->
    Pid = spawn(my, nothing, []),
    lists:concat(["hello", pid_to_list(Pid)]).

nothing() -> nothing.

In the shell:

4> c(my).  
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}

5> my:go().
"hello<0.83.0>"

From the erl docs :

concat(Things) -> string()
    Things = [Thing]
    Thing = atom() | integer() | float() | string()

The list that you feed concat() must contain either atoms, integers, floats, or strings. A pid is neither an atom, integer, float, nor string, so a pid cannot be used with concat(). However, pid_to_list() returns a string:

pid_to_list(Pid) -> string()
    Pid = pid()

As you can see, a pid has its own type: pid().

I ran your code. Where you went wrong was to pass Process_id (which is of type pid() ) to lists:concat/1 .

Let us try to understand this error:

{function_clause,[{lists,thing_to_list,
                         [<0.84.0>],
                         [{file,"lists.erl"},{line,603}]},
                  {lists,flatmap,2,[{file,"lists.erl"},{line,1250}]},
                  {lists,flatmap,2,[{file,"lists.erl"},{line,1250}]},
                  {prog,friends,4,[{file,"prog.erl"},{line,39}]}]}

It states the function lists:thing_to_list/1 has no definition(see the word function_clause in the error log) which accepts an argument of type pid() as denoted here by [<0.84.0>] .

Strings are represented as lists in erlang, which is why we use lists:concat/1.

As @7stud pointed out these are the valid types which can be passed to lists:concat/1 as per the documentation :

atom() | integer() | float() | string()

There are 2 occurrences of the following line. Fix them and you are good to go:

Incorrect Code:

M_pid!{lists:concat([Self_name," received intro message from ", Process_name , "[",Process_id,"]"]), self()},

Corrected Code

M_pid!{lists:concat([Self_name," received intro message from ", Process_name , "[",pid_to_list(Process_id),"]"]), self()},

Notice the use of the function erlang:pid_to_list/1 . As per the documentation the function accepts type pid() and returns it as string() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM