Изменить состояние gen_fsm на функцию в другом модуле

У нас есть довольно большое USSD-приложение, которое использует модуль 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/1 а также waitHelpMenuChoice/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 ответа

Может быть, вы могли бы использовать http://www.erlang.org/doc/man/gen_fsm.html для этого? Не уверен, что это будет работать, чтобы вызвать его внутри другого ФСМ, но это может стоить попробовать.

Мне удалось найти решение моего собственного вопроса. Если это кажется очевидным, это может быть потому, что я немного новичок в Эрланге.

Я добавил новую функцию 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/2, help_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).

но я думаю, что мое объяснение выше иллюстрирует идею лучше.

Другие вопросы по тегам