Изменить состояние 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).
но я думаю, что мое объяснение выше иллюстрирует идею лучше.