В Erlang, как вы вызываете функцию динамически?
Я хочу вызвать xyz с именем вызываемой функции.
-module(sample).
-export([xyz/1]).
xyz(Name) -> Name().
p() -> "you called p".
g() -> "you called g".
Но я получаю следующую ошибку:
1> c(sample.erl).
./sample.erl:6: Warning: function p/0 is unused
./sample.erl:7: Warning: function g/0 is unused
{ok,sample}
2> sample:xyz('p').
** exception error: bad function p
in function sample:xyz/1
3>
Ответы
Ответ 1
Правильно, что вам нужно экспортировать p и g. Затем вы можете использовать apply/3 для его вызова.
erlang:apply(sample, p, [])
Только забавные значения можно использовать с синтаксисом Fun (...). Вы передаете значение атома. Атом - это "плохая функция", так как сообщение об ошибке идет. Вы можете сделать что-то похожее на
xyz(p) -> fun p/0;
xyz(g) -> fun g/0.
Затем перейдите и вызовите
Fun = xyz(p),
Fun()
Ответ 2
-module(sample).
-export([xyz/1, p/0, g/0]).
xyz(Name) -> ?MODULE:Name().
p() -> "you called p".
g() -> "you called g".
1> sample:xyz(p).
"you called p"
Ответ 3
Сравнение шаблонов - это идиома, которую следует использовать:
-module(sample).
-export([xyz/1]).
xyz(p) -> p();
xyz(q) -> g().
p() -> "you called p".
g() -> "you called g".
Если вы хотите быть динамическим, вы можете использовать сервер gen_event.
По сути, это сервер, который содержит состояние, состоящее из пары ключ/функция, например:
[{p, #func1},
{g, #func2},
{..., ...},
...]
Затем вы можете существенно привязать события к функциям. (есть, разумеется, немного больше, чем это.
Ответ 4
Самый простой способ - попробовать экспортировать p и g вместе с xyz.
-export([xyz/1, p/0,g/0]).
После экспорта функции p и g можно вызвать следующим образом:
1> sample:xyz(fun sample:p/0).
"you called p"
2> sample:xyz(fun sample:g/0).
"you called g"
Ответ 5
Другим способом взглянуть на это является то, что (в зависимости от проблемы, которую вы решаете) динамические вызовы функций не всегда являются правильным подходом. Учитывая, что процессы и передача сообщений - это способ организации вашего кода в Erlang, поскольку это "ориентированный на concurrency язык", возможно, вы могли бы просто использовать передачу сообщений с выборочным приемом, а не имитировать идиомы последовательного языка? Отправьте сообщение, для чего вы хотите, и получите его на основе этого. Это ведь результат каждой функции, а не сама функция, в конце концов. (Кроме того, гибкость и масштабируемость передачи сообщений и т.д.)
Несмотря на то, что процессы не являются полностью бесплатными по сравнению с вызовом из библиотечного модуля, процессы уровня Erlang являются грязными (особенно, если связь сообщений находится в пределах одного и того же node). Они не являются процессами на уровне ОС. Накладные расходы были бы сопоставимы (или лучше) с динамическими вызовами функций и созданием объектов на более тяжелых языках сценариев.