In Erlang, how do you invoke a function dynamicall

2020-07-02 11:24发布

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>

标签: erlang
5条回答
Melony?
2楼-- · 2020-07-02 11:54

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.

查看更多
Ridiculous、
3楼-- · 2020-07-02 11:55

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"
查看更多
够拽才男人
4楼-- · 2020-07-02 12:06

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()
查看更多
Fickle 薄情
5楼-- · 2020-07-02 12:11

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.

查看更多
Root(大扎)
6楼-- · 2020-07-02 12:17
-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"
查看更多
登录 后发表回答