将gen_fsm状态更改为其他模块中的函数

时间:2012-04-05 07:59:43

标签: erlang gen-fsm

我们有一个相当大的USSD应用程序,它使用Erlang的gen_fsm模块来管理菜单选项。

当前版本有一个menus_fsm.erl文件,其中包含5000+行gen_fsm相关代码。我们的下一个版本让我们有机会将menus_fsm.erl拆分为单独的文件,以便将来更易于维护。

在旧版本中,为了显示帮助菜单,我们执行以下操作(从显示主菜单的未显示代码调用help_menu/1):

-module(menus_fsm).    
% Snipped some irrelvant code

help_menu(StateData) ->
    % Display the first menu
    send_menu(StateData, "Please Select:\n1. Option 1\n2. Option 2"),
    {next_state, waitHelpMenuChoice, StateData, ?MENU_TOUT};

waitHelpMenuChoice(Params, StateData) ->
    io:format("Got Help menu response: ~p", [Params]),
    doTerminate(ok,"Help Menu", StateData).

我遗漏了很多代码,显示了进入FSM的入口点等等。

在新版本中,我们希望将help_menu/1waitHelpMenuChoice/2移动到新模块help_menu,该模块将从menus_fsm调用,如下所示:

-module( help_menu ).    
% Snipped some irrelevant code

help_menu(StateData) ->
    menus_fsm:send_menu(StateData, "Please Select:\n1. Option 1\n2. Option 2"),
    {next_state, waitHelpMenuChoice, StateData, ?MENU_TOUT};

waitHelpMenuChoice(Params, StateData) ->
    io:format("Got Help menu response: ~p", [Params]),
    menus_fsm:doTerminate(ok,"Help Menu", StateData).

问题在于行{next_state, waitHelpMenuChoice, StateData, ?MENU_TOUT};gen_fsm期望waitHelpMenuChoice位于模块menus_fsm中,这会将我带回到我们开始的位置。

我试图用

替换有问题的行
{next_state, fun help_menu:waitHelpMenuChoice/2, StateData, ?MENU_TOUT};

但这只是出现如下错误: {badarg,[{erlang,apply,[conv_fsm,#Fun<help_menu.waitHelpMenuChoice.2>,[]]}

有没有人对如何解决这个问题有任何建议?

2 个答案:

答案 0 :(得分:0)

也许您可以使用http://www.erlang.org/doc/man/gen_fsm.html#enter_loop-6来做到这一点?不确定它是否可以在另一个fsm中调用它,但它可能值得一试。

答案 1 :(得分:0)

我设法找到了解决自己问题的方法。如果这看起来很明显,可能是因为我对Erlang有点新鲜。

我向模块wait_for_menu_response/2添加了一个新函数menus_fsm,它代表其他模块处理状态转换。

-module(menus_fsm),
-export([wait_for_menu_response/2]).
% ...snip...
wait_for_menu_response(Params, {Function, StateData}) ->
    Function(Params, StateData).

然后help_menu模块更改如下:

-module( help_menu ).    
% ...snip...

help_menu(StateData) ->
    menus_fsm:send_menu(StateData, "Please Select:\n1. Option 1\n2. Option 2"),
    {next_state, wait_for_menu_response, {fun waitHelpMenuChoice/2, StateData}, ?MENU_TOUT}.

waitHelpMenuChoice(Params, StateData) ->
    io:format("Got Help menu response: ~p", [Params]),
    menus_fsm:doTerminate(ok,"Help Menu", StateData).

所以gen_fsm在调用menus_fsm时会保留在wait_for_menu_response模块中,但wait_for_menu_response现在可以自由调用help_menu:waitHelpMenuChoice/2help_menu:waitHelpMenuChoice/2不需要以任何方式进行修改。

实际上,在我的最终版本中,menus_fsm:send_menu函数已被修改为接受fun waitHelpMenuChoice/2作为其第三个参数,因此help_menu函数只会变为:

help_menu(StateData) ->
    menus_fsm:send_menu(StateData, "Please Select:\n1. Option 1\n2. Option 2", 
        fun waitHelpMenuChoice/2).

但我认为我上面的解释更好地说明了这个想法。