Erlang 我是否可以修改由具有外部功能的gen_服务器管理的地图?

Erlang 我是否可以修改由具有外部功能的gen_服务器管理的地图?,erlang,gen-server,Erlang,Gen Server,我有一个映射,它由一个具有gen_服务器行为的模块管理,我可以在其中添加、删除和更新key->value 我还有一个主模块,其中包含一些例程和子例程,根据映射中的键->值进行操作。我的问题是,我试图在模块执行期间修改映射,但没有得到任何答案 这是我的主要模块的结构示例: -export([ go/0, add_belief/1 ]). go()-> bs:start_link(), collect_bottles(0). collect_bottles

我有一个映射,它由一个具有gen_服务器行为的模块管理,我可以在其中添加、删除和更新key->value

我还有一个主模块,其中包含一些例程和子例程,根据映射中的键->值进行操作。我的问题是,我试图在模块执行期间修改映射,但没有得到任何答案

这是我的主要模块的结构示例:

-export([
    go/0, 
    add_belief/1
]).

go()->
    bs:start_link(),
    collect_bottles(0).

collect_bottles(Total) ->
    case {bs:is_belief(holding), bs:is_belief(over_drop)} of
        {true, true} -> drop_and_leave();
        {true,false} -> get_to_drop();
        {false, _} -> get_bottle()
    end.

get_bottle()->
io:format("Getting bottle.~n"),
case {bs:get_belief(see)} of
    {true} -> collect_bottles(bs:get_belief(collected)); 
    {false} ->move(),
              get_bottle()
end.

move(Dist)->
io:format("Start moving...~n"),
timer:sleep(5000).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%            GOD FUNCTIONS             %%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

add_belief(Belief)->
    bs:add_belief(Belief).
bs:add_信念(信念)
的代码为:

add_belief(Belief)->
    gen_server:cast(?MODULE,{add,Belief}).
genu服务器
功能中:

handle_cast({add,{Key,Value}},State)->
    io:format("Belief added: ~p.~n",[{Key,Value}]),
    {noreply, maps:put(Key,Value,State)};
当我运行脚本时,我得到:

tr:go().
Getting bottle.
Start moving...
Getting bottle.
Start moving...
我不能使用另一个函数(我想使用
add_-belience({see,瓶子})
来摆脱循环

我是否可以修改由带有外部服务器的gen_服务器管理的映射 功能

是的,这是证据:

$ erl
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.2  (abort with ^G)

1> c(tr).
{ok,tr}

2> c(bs).
{ok,bs}

3> c(env).
{ok,env}

4> tr:test().
tr:get_bottle(): getting bottle
<0.74.0>
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle

5> env:get_state().
env: get_state(): 10
ok
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle

6> bs:get_state().
bs:get_state(): #{}
ok
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle 

7> bs:add_belief({holding, []}).
Adding belief: {holding,[]}
ok
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle

8> bs:get_state().
bs:get_state(): #{holding=>[]}
ok
tr:get_bottle(): getting bottle

9> 
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
       (v)ersion (k)ill (D)b-tables (d)istribution
$ 
然后就是这样:

1> c(tr).
{ok,tr}

2> c(bs).
{ok,bs}

3> c(env).
{ok,env}

4> tr:test().
tr:get_bottle(): getting bottle
<0.74.0>
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle 

5> bs:add_belief({holding, []}).
ok
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle

6> bs:get_state().
** exception exit: {noproc,{gen_server,call,[bs,get_state]}}
     in function  gen_server:call/2 (gen_server.erl, line 204)
     in call from bs:get_state/0 (bs.erl, line 40)
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
tr:get_bottle(): getting bottle
要获取服务器PID,需要执行以下操作:

start_link() ->
    gen_server:start_link(
      %%{local, ?MODULE},
      ?MODULE, [], []
    ).
 gen_server:call(ServerPid, Request)
start_link() ->
    {ok, ServerPid} = gen_server:start_link(
                          %%{local, ?MODULE},
                          ?MODULE, [], []
                      ),
    ServerPid.
从上面的最后一个shell会话来看,如果您没有指定
{local,ServerName}
——因此您没有注册服务器名称——并且您调用
gen\u server:cast(?MODULE…)
不会导致错误,但是如果调用
gen\u server:call(?MODULE…)
您将得到一个错误。在我看来,如果您在服务器未注册的情况下在这两种情况下都得到了一个错误,那么它会很方便——演员阵容的
ok
返回值非常容易误导


tr.erl

-module(tr).
%%-compile(export_all).
-export([go/0, test/0]).

go() ->
    bs:start_link(),
    env:start_link(),
    collect_bottles(0).

collect_bottles(_Total) ->
    get_bottle().

get_bottle() ->
    io:format("tr:get_bottle(): getting bottle~n"),
    timer:sleep(3000),
    get_bottle().

test() ->
    spawn(tr, go, []).
-module(bs).
%%-compile(export_all).
-export([init/1, handle_call/3, handle_cast/2]).
-export([handle_info/2, terminate/2, code_change/3]).
-export([start_link/0, add_belief/1, get_state/0, stop/0]).


%%Internal server functions:
init([]) ->
    {ok, #{}}.  %%<******** INITIALIZE STATE WITH AN EMPTY MAP

handle_cast({add, {Key, Val}=Belief}, State) ->
    io:format("Adding belief: ~w~n", [Belief]),
    { noreply, maps:put(Key, Val, State) }.

handle_call(get_state, _From, State) ->
    {reply, State, State}.    

%  -----
handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%External interface:
start_link() ->
    gen_server:start_link(
      {local, ?MODULE},
      ?MODULE, [], []
    ).

add_belief(Belief) ->  %%<******* EXTERNAL FUNCTION THAT MODIFIES A MAP
    gen_server:cast(?MODULE, {add, Belief}).

get_state() ->
    State = gen_server:call(?MODULE, get_state),
    io:format("bs:get_state(): ~w~n", [State]).

stop() ->
    gen_server:stop(?MODULE).
-module(env).
%%-compile(export_all).
-export([init/1, handle_call/3, handle_cast/2]).
-export([handle_info/2, terminate/2, code_change/3]).
-export([start_link/0, get_state/0, stop/0]).

%%Internal server functions:
init([]) ->
    {ok, 10}.   %%<***** INITIALIZE STATE WITH 10

handle_call(get_state, _From, State) ->
    {reply, State, State}.

%%     ------
handle_cast(_Request, State) ->
    {noreply, State}.    

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%External interface:
start_link() ->
    gen_server:start_link(
      {local, ?MODULE},
      ?MODULE, [], []
    ).

get_state() ->
    State = gen_server:call(?MODULE, get_state),
    io:format("env: get_state(): ~w~n", [State]).

stop() ->
    gen_server:stop(?MODULE).
bs.erl

-module(tr).
%%-compile(export_all).
-export([go/0, test/0]).

go() ->
    bs:start_link(),
    env:start_link(),
    collect_bottles(0).

collect_bottles(_Total) ->
    get_bottle().

get_bottle() ->
    io:format("tr:get_bottle(): getting bottle~n"),
    timer:sleep(3000),
    get_bottle().

test() ->
    spawn(tr, go, []).
-module(bs).
%%-compile(export_all).
-export([init/1, handle_call/3, handle_cast/2]).
-export([handle_info/2, terminate/2, code_change/3]).
-export([start_link/0, add_belief/1, get_state/0, stop/0]).


%%Internal server functions:
init([]) ->
    {ok, #{}}.  %%<******** INITIALIZE STATE WITH AN EMPTY MAP

handle_cast({add, {Key, Val}=Belief}, State) ->
    io:format("Adding belief: ~w~n", [Belief]),
    { noreply, maps:put(Key, Val, State) }.

handle_call(get_state, _From, State) ->
    {reply, State, State}.    

%  -----
handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%External interface:
start_link() ->
    gen_server:start_link(
      {local, ?MODULE},
      ?MODULE, [], []
    ).

add_belief(Belief) ->  %%<******* EXTERNAL FUNCTION THAT MODIFIES A MAP
    gen_server:cast(?MODULE, {add, Belief}).

get_state() ->
    State = gen_server:call(?MODULE, get_state),
    io:format("bs:get_state(): ~w~n", [State]).

stop() ->
    gen_server:stop(?MODULE).
-module(env).
%%-compile(export_all).
-export([init/1, handle_call/3, handle_cast/2]).
-export([handle_info/2, terminate/2, code_change/3]).
-export([start_link/0, get_state/0, stop/0]).

%%Internal server functions:
init([]) ->
    {ok, 10}.   %%<***** INITIALIZE STATE WITH 10

handle_call(get_state, _From, State) ->
    {reply, State, State}.

%%     ------
handle_cast(_Request, State) ->
    {noreply, State}.    

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%External interface:
start_link() ->
    gen_server:start_link(
      {local, ?MODULE},
      ?MODULE, [], []
    ).

get_state() ->
    State = gen_server:call(?MODULE, get_state),
    io:format("env: get_state(): ~w~n", [State]).

stop() ->
    gen_server:stop(?MODULE).

你到底想做什么,什么不起作用?我执行go(),它开始工作。然后,在执行过程中,我从shell中添加信念(信念),以更改映射和对案例其他语句的访问。例如:我的映射是{holding=>[],over_drop=>[]),因此在collect_瓶子中,我可以访问{true,true}->drop_and_leave。现在我想添加_-Elidence({gripper_-open,[]),以便能够访问drop_and_-leave()中的true语句,但它没有任何作用。您应该发布
bs:add_-Elidence(Elidence)的代码
我无法帮助您查看代码。在另一个句柄\u cast中添加一个print语句。在不知道您在shell中写了什么的情况下,我可以安全地猜测您输入了错误的元组。如果您提供的start\u link()函数与您指示的相同,则会更好。我再次编辑了我的帖子(尝试做更好的MCVE),因为我没有意识到我在使用Erlide,这就是为什么我可以在控制台中编写,但我没有得到任何答案。如果我从werl运行,我无法在脚本运行时引入新命令。@Antolinos95,我无法在脚本运行时引入新命令。--我认为您有两个选项:1)生成go()功能。看看我在test()函数中是如何做到这一点的?2) 将所有要运行的erlang shell命令放在go()中,并穿插一些
timer:sleep()
。@Antolinos95,事实上,在测试代码时,我甚至没有输入erlang shell来编译您的三个模块——这太痛苦了。相反,我创建了一个名为
run
的bashshell脚本来为我进行编译,其中包含以下行:
#/usr/bin/env bash
erlc-W tr.erl env.erl bs.erl
erl-s tr测试
。这样,我只需在第一次运行您的程序时在命令行中键入
$./运行
,然后用Ctrl+CC终止erlang shell,要重新编译并再次运行,我只需按向上箭头键进入上一个命令:
/run
,然后按Return.@Antolinos95,如果您想节省大量时间和沮丧,了解如何在windows上执行等效操作。您可以使用批处理文件、perl、ruby、python或makefile来运行这些erlang命令。至少,您应该能够像这样从命令行编译:
$erlc-W tr.erl bs.erl env.erl
然后
$erl-s tr go
并将所有erlang shell命令放在go()中。然后您可以使用
Ctrl+CC
杀死erlang shell,然后通过点击向上箭头进入前面的命令并点击Return重新编译并运行,这将节省您大量的键入时间。关于erlang编译,我使用Eclipse的一个扩展来处理它,因为对于我(我是初学者)来说,它更容易,因为我使用了Eclipse和Java。