Почему я получаю дважды одно и то же сообщение?

Я новичок в Erlang, и я разрабатываю небольшую программу для моделирования робота, который собирает банки:

-export([start/0]).

start()->
    Believes=#{bin_position=>0, num_cans=>1, can_position=>4, my_position=>1},
    PID=spawn(fun()-> believes(Believes) end),
    action(PID,Believes).

believes(NewBelieves)->

    receive
        {add,Key,Value}->
            N1=maps:put(Key,Value,NewBelieves),
            print(N1),
            action(self(),N1),
            believes(N1);
        {remove, Key}->
            N2=maps:remove(Key, NewBelieves),
            print(N2),
            action(self(),N2),
            believes(N2);
        {update, Key, Value}->
            N3=NewBelieves#{Key => Value},
            print(N3),
            action(self(),N3),
            believes(N3);
        {get}->
            action(self(),NewBelieves),
            believes(NewBelieves)
    end.

print(Map)->
    List=maps:to_list(Map),
    io:format("Believes: ~p~n",[List]).

action(PID, Map)->
    case {is_holding(Map),is_over_bin(PID,Map)} of
            {false,false}->
                %io:format("Is not holding and is not over the bin ~n"),
                %timer:sleep(1000),
                case is_over_can(PID,Map) of
                    false->move(PID,right,Map);
                          % timer:sleep(1000);
                    _->hold(PID)
                       %timer:sleep(1000)
               end;
            {_,false}->
                %io:format("Is holding but is not over the bin ~n"),
                %timer:sleep(1000),
                move(PID, left, Map);
                %timer:sleep(1000);
            {_,_}->
                %io:format("Is holding and is over the bin ~n"),
                %timer:sleep(1000),
                drop(PID),
                timer:sleep(10000),
                exit(self(),kill)
        end.

is_over_can(PID, Map)->
    case same_position(maps:find(my_position,Map),maps:find(can_position, Map)) of
        equal->hold(PID);
        _->false
    end.

is_over_bin(PID, Map)->
    case same_position(maps:find(my_position,Map),maps:find(bin_position, Map)) of
        equal->drop(PID);
        _->false
    end.

is_holding(Map)->
    maps:is_key(holding,Map).

%is_gripper_on(Map)->
%   map:is_key(gripper_on,Map).
%is_touching(Map)->
%   map:is_key(touching,Map).

same_position({ok,A},{ok,B}) when A=:=B -> equal;
same_position(_, _) -> not_equal.

move(PID, Dir, Map)->
    {ok,MyPosition}=maps:find(my_position,Map),
    case Dir of
        right->PID ! {update, my_position, MyPosition+1};
        left->PID ! {update, my_position, MyPosition-1}
    end.  

hold(PID)->
    PID ! {add, holding, []},
    PID ! {update, can_position, nil}.

drop(PID)->
    PID ! {remove, holding},
    PID ! {update, num_cans, 0},
    PID ! {add, cans_collected, 1},
    timer:sleep(10000),
    io:format("Todas las latas han sido recogidas.~n"),
    timer:sleep(10000),
    exit(PID,kill).

И когда я запускаю код, в некоторых случаях я получаю отпечаток дважды (и я не получаю последние 3 отпечатка из функции перетаскивания):

пруэба2:старт().

Верит: [{bin_position,0},{can_position,4},{my_position,2},{num_cans,1}]

Верит: [{bin_position,0},{can_position,4},{my_position,3},{num_cans,1}]

{обновление, моя_позиция, 2}

Верит: [{bin_position,0},{can_position,4},{my_position,4},{num_cans,1}]

(Prueba@Usuario)2> Верит: [{bin_position,0}, {can_position,4}, {holding,[]}, {my_position,4}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,4}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,4}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,4}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,3}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,3}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,3}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,3}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,2}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,2}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,2}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,2}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,1}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,1}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,1}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,1}, {num_cans,1}]

Верит: [{bin_position,0}, {can_position,nil}, {holding,[]}, {my_position,0}, {num_cans,1}]

Todas las latas han sido recogidas.

Я делаю что-то неправильно? Связано ли это со временем, которое требуется каждому процессу для его выполнения? Я также не знаю, есть ли способ реализовать это с помощью OTP, я имею в виду, используя gen_server или что-то в этом роде.

Большое спасибо!


person Antolinos95    schedule 07.05.2017    source источник
comment
Каков ожидаемый результат здесь? Пожалуйста, создайте минимальный пример, удалив ненужный код, трудно понять, что именно делает этот код. stackoverflow.com/help/mcve   -  person Dogbert    schedule 08.05.2017
comment
Я должен получить только 1 сообщение каждого из них. Я решил это с помощью поведения gen_server, если вы знаете, как его использовать, это потрясающе! Спасибо за ваши ответы: Д.   -  person Antolinos95    schedule 17.05.2017


Ответы (1)


Попробуйте запустить этот код:

-module(so1).
-export([start/0]).

start()->
    Believes = #{bin_position=>0, num_cans=>1, can_position=>4, my_position=>1},
    PID = spawn(fun()-> believes(Believes) end),
    action(PID,Believes).

believes(NewBelieves)->

    receive
        {add,Key,Value}->
            N1=maps:put(Key,Value,NewBelieves),
            io:format("add clause:~n"),
            print(N1),
            action(self(),N1),
            believes(N1);
        {remove, Key}->
            N2=maps:remove(Key, NewBelieves),
            io:format("remove clause:~n"),
            print(N2),
            action(self(),N2),
            believes(N2);
        {update, Key, Value}->
            N3=NewBelieves#{Key => Value},
            io:format("update clause:~n"),
            print(N3),
            action(self(),N3),
            believes(N3);
        {get}->
            action(self(),NewBelieves),
            believes(NewBelieves)
    end.

print(Map)->
    List=maps:to_list(Map),
    io:format("Believes: ~p~n",[List]).

action(PID, Map)->
    case {is_holding(Map),is_over_bin(PID,Map)} of
            {false,false}->
                %io:format("Is not holding and is not over the bin ~n"),
                %timer:sleep(1000),
                case is_over_can(PID,Map) of
                    false->
                        io:format("action() is calling move()~n"),
                        move(PID,right,Map);
                          % timer:sleep(1000);
                    _->hold(PID)
                       %timer:sleep(1000)
               end;
            {_,false}->
                %io:format("Is holding but is not over the bin ~n"),
                %timer:sleep(1000),
                move(PID, left, Map);
                %timer:sleep(1000);
            {_,_}->
                %io:format("Is holding and is over the bin ~n"),
                %timer:sleep(1000),
                drop(PID),
                timer:sleep(10000),
                exit(self(),kill)
        end.

is_over_can(PID, Map)->
    case same_position(maps:find(my_position,Map),maps:find(can_position, Map)) of
        equal->hold(PID);
        _->false
    end.

is_over_bin(PID, Map)->
    case same_position(maps:find(my_position,Map),maps:find(bin_position, Map)) of
        equal->drop(PID);
        _->false
    end.

is_holding(Map)->
    maps:is_key(holding,Map).

%is_gripper_on(Map)->
%   map:is_key(gripper_on,Map).
%is_touching(Map)->
%   map:is_key(touching,Map).

same_position({ok,A},{ok,B}) when A=:=B -> equal;
same_position(_, _) -> not_equal.

move(PID, Dir, Map)->
    {ok,MyPosition}=maps:find(my_position,Map),
    io:format("move() is going to send update message~n"),
    case Dir of
        right-> PID ! {update, my_position, MyPosition+1};
        left -> PID ! {update, my_position, MyPosition-1}
    end.  

hold(PID)->
    io:format("hold() is sending add, update messages,~n"),
    io:format("which will result in two prints:~n"),
    PID ! {add, holding, []},
    PID ! {update, can_position, nil}.

drop(PID)->
    io:format("drop() is sending remove, update, add messages,~n"),
    io:format("which will result in three prints:~n"),
    PID ! {remove, holding},
    PID ! {update, num_cans, 0},
    PID ! {add, cans_collected, 1},
    timer:sleep(10000),
    io:format("Todas las latas han sido recogidas.~n"),
    timer:sleep(10000),
    exit(PID,kill).

Вывод покажет, что ваш код представляет собой запутанный беспорядок. Кроме того, когда вы создаете более одного процесса, выходные данные могут чередоваться и поступать в порядке, отличном от написанного.

Я совсем новичок в Erlang,

Вы можете кодировать только те программы, которые могут справиться с вашими навыками отладки. Пока придерживайтесь 20 строк или меньше. Вы также можете попробовать использовать отладчик erlang для выполнения кода.

Я также не знаю, есть ли способ реализовать это с помощью OTP, я имею в виду, используя gen_server или что-то в этом роде.

Любой бесконечный цикл с предложением получения и переменной цикла, которая содержит состояние, может считаться сервером, поэтому believes() можно реализовать как gen_server.

person 7stud    schedule 08.05.2017