2009-08-21 22 views
13

Quiero llamar a xyz con el nombre de una función para invocar.En Erlang, ¿cómo invocas dinámicamente una función?

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

xyz(Name) -> Name(). 

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

pero me da el siguiente 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> 
+2

Mi conocimiento de Erlang es cercano a cero, pero supongo que tiene que exportar p (y, posiblemente, g, si se desea para usarlo) también. – balpha

Respuesta

22

Es cierto que tiene que exportar py g. Luego puede usar apply/3 para llamarlo.

erlang:apply(sample, p, []) 

Solo los valores divertidos se pueden usar con la sintaxis Fun (...). Estás pasando un valor atómico. Un átomo es una "mala función" como dice el mensaje de error. Se podría hacer algo similar a

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

continuación, seguir adelante y llamar a

Fun = xyz(p), 
Fun() 
+0

Gracias. Ahora tengo esto: -module (sample). -export ([xyz/1, p/0, g/0]). xyz (Nombre) -> aplicar (muestra, nombre, []). p() -> "has llamado p". g() -> "has llamado g". y soy capaz de hacer: 26> c (sample.erl). {ok, muestra} 27> muestra: xyz ('p'). "llamó a p" 28> muestra: xyz (p). "llamó a p" 29> muestra: xyz ('g'). "has llamado g" 30> muestra: xyz (g). "has llamado g" ¿Pero no hay una forma de no exportar estas funciones? No quiero que sea visible para los usuarios del módulo. Parece que tampoco funciona con apply/2. Por supuesto, soy un novato de erlang – ottodidakt

+1

Usted codifica su mapeo de llamadas con coincidencia de patrones o exporta sus funciones. – Zed

+0

La única forma de 'filtrar' una función no exportada es devolver un valor divertido que se refiera a ella. Al igual que mi función xyz/1 explícita que devuelve un valor divertido. – Christian

7

partido de patrones es el idioma a utilizar:

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

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

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

Si quieres ser dinámico se puede utilizar una gen_event servidor.

Esencialmente lo que se trata es un servidor que tiene un estado que consiste en un par de claves/función de este modo:

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

A continuación, puede unirse a eventos esencialmente funciones. (No, no hace falta decir, un poco más que eso.

+1

si bien esto es técnicamente una forma de hacerlo, creo que la pregunta está más orientada a la mecánica en erlang el lenguaje para llamar dinámicamente a una función. La función de aplicar es la respuesta que está buscando. –

8
-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" 
+1

Eso es genial. ¿Dónde puedo leer sobre "? MODULE"? Ahora si solo pudiéramos terminar exportando pyq. – ottodidakt

+0

Aquí están las macros predefinidas: http://erlang.org/doc/reference_manual/macros.html#7.3. Desafortunadamente, Erlang solo tiene visibilidad "pública" y "privada", pero no cuenta con protección y paquete protegidos. Entonces, o lo exporta o "codifica" las llamadas. – Zed

+1

Pero ¿por qué no estoy obligado a exportar en caso de una llamada enlazada estáticamente xyz (Nombre) -> p(). y se requiere exportar cuando está vinculado dinámicamente? Pensando en términos de visibilidad "privada", estoy en un ámbito privado, ¿no es así? – ottodidakt

0

Otra forma de verlo es que (en función del problema que se está resolviendo) llamadas a funciones dinámicas no es necesariamente la Enfoque correcto: dado que los procesos y el envío de mensajes son la forma de organizar el código en Erlang, ya que es un "lenguaje orientado a la concurrencia", ¿podría simplemente usar mensajes con una recepción selectiva en lugar de imitar idiomas de un lenguaje secuencial? Enviar un mensaje para lo que quiere y obtenga la respuesta personalizada basada en eso. Se trata del resultado de cada función, no de la función en sí, después de todo. (Además, existe la flexibilidad y escalabilidad del envío de mensajes, etc.)

Alt Si bien los procesos no son totalmente gratuitos en comparación con las llamadas desde un módulo de biblioteca, los procesos a nivel de Erlang son extremadamente baratos (especialmente si la comunicación del mensaje está dentro del mismo nodo). No son procesos a nivel de sistema operativo. La sobrecarga sería comparable (o mejor) a las llamadas a funciones dinámicas y la instanciación de objetos en lenguajes de scripting más pesados.

1

La manera más fácil de hacerlo es intentar exportar p y g junto con xyz.

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

Después de exportar la función p y g puede ser llamado como sigue:

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