Erlang 我是否可以修改由具有外部功能的gen_服务器管理的地图?
我有一个映射,它由一个具有gen_服务器行为的模块管理,我可以在其中添加、删除和更新key->value 我还有一个主模块,其中包含一些例程和子例程,根据映射中的键->值进行操作。我的问题是,我试图在模块执行期间修改映射,但没有得到任何答案 这是我的主要模块的结构示例: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
-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。