In Erlang, how do you invoke a function dynamically?

夙愿已清 提交于 2019-12-05 13:39:15

问题


I want to call xyz with the name of a function to be invoked.

-module(sample).
-export([xyz/1]).

xyz(Name) -> Name().

p() -> "you called p".
g() -> "you called g".

But I get the following error:

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:


It is correct that you have to export p and g. You can then use apply/3 to call it.

erlang:apply(sample, p, [])

Only fun-values are usable with the Fun(...) syntax. You are passing in an atom-value. An atom is a 'bad function' as the error message go. You could do something similar to

xyz(p) -> fun p/0;
xyz(g) -> fun g/0.

Then go ahead and call

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:


Pattern match is the idiom to use:

-module(sample).
-export([xyz/1]).

xyz(p) -> p();
xyz(q) -> g().

p() -> "you called p".
g() -> "you called g".

If you want to be dynamic you can use a gen_event server.

Essentially what this is is a server that holds a state which consists of key/function pair like so:

[{p, #func1},
 {g, #func2},
 {..., ...},
 ...]

You can then essentially bind events to functions. (there is, needless to say, a bit more to it than that.




回答4:


The easiest way to do is to try exporting p and g along with xyz.

-export([xyz/1, p/0,g/0]).

After exporting the function p and g can be called as follows :

1> sample:xyz(fun sample:p/0).
"you called p"
2> sample:xyz(fun sample:g/0).
"you called g"



回答5:


Another way to look at it is that (depending on the problem you're solving) dynamic calls to functions isn't necessarily the right approach. Given that processes and message passing are the way you organize your code in Erlang since it's a "concurrency oriented language", maybe you could just use message passing with a selective receive rather than mimicking idioms of a sequential language? Send a message for what you want and get the custom reply based on that. It's about the result of each function, not the function itself, after all. (Plus there's the flexibility and scalability of message passing, etc.)

Although processes aren't totally free compared to calling from a library module, Erlang-level processes are dirt cheap (especially if the message communication is within the same node). They're not OS-level processes. The overhead would be comparable (or better) to dynamic function calls and object instantiation in heavier scripting languages.



来源:https://stackoverflow.com/questions/1310382/in-erlang-how-do-you-invoke-a-function-dynamically

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!