2009-08-21 12 views
13

Voglio chiamare xyz con il nome di una funzione da invocare.In Erlang, come si attiva dinamicamente una funzione?

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

xyz(Name) -> Name(). 

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

ma ottengo il seguente errore:

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

La mia conoscenza Erlang è vicino a zero, ma suppongo che è necessario esportare p (e, eventualmente, g, se si desidera usarlo) pure. – balpha

risposta

22

è giusto che si deve esportare p e g. È quindi possibile utilizzare apply/3 per chiamarlo.

Solo i valori di divertimento sono utilizzabili con la sintassi Fun (...). Stai trasmettendo un valore atomico. Un atomo è una "cattiva funzione" quando il messaggio di errore scompare. Si potrebbe fare qualcosa di simile a

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

poi andare avanti e chiamare

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

Grazie. Ora ho questo: -modulo (esempio). -export ([xyz/1, p/0, g/0]). xyz (Nome) -> applica (campione, nome, []). p() -> "hai chiamato p". g() -> "hai chiamato g". e sono in grado di fare: 26> c (sample.erl). {ok, campione} 27 esempio: xyz ('p'). "hai chiamato p" 28> esempio: xyz (p). "hai chiamato p" 29> esempio: xyz ('g'). "hai chiamato g" 30> esempio: xyz (g). "hai chiamato g" Ma non c'è un modo per non esportare queste funzioni? Non voglio che sia visibile agli utenti del modulo. Non riesco a farlo funzionare anche con apply/2. Naturalmente, sono un principiante di erlang – ottodidakt

+1

È possibile eseguire l'hard-code del mapping delle chiamate con la corrispondenza del modello o esportare le proprie funzioni. – Zed

+0

L'unico modo per "scoprire" una funzione non esportata è restituire un valore divertente che si riferisce ad esso. Proprio come la mia esplicita funzione xyz/1 che restituisce un valore divertente. – Christian

7

pattern match è il linguaggio da usare:

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

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

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

Se si vuole essere dinamica è possibile utilizzare un gen_event server.

In sostanza ciò che questo è è un server che contiene uno stato che consiste di coppia chiave/funzione in questo modo:

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

È possibile quindi essenzialmente associare eventi alle funzioni. (V'è, manco a dirlo, un po 'più ad esso che quello.

+1

mentre questo è tecnicamente un modo per farlo penso che la domanda sia più orientata alla meccanica in grado di chiamare dinamicamente una funzione. La funzione apply è la risposta che sta cercando. –

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

È davvero fantastico. Dove posso leggere "MODULO"? Ora se solo potessimo eliminare esportando p e q. – ottodidakt

+0

Ecco le macro predefinite: http://erlang.org/doc/reference_manual/macros.html#7.3. Purtroppo Erlang ha solo visibilità "pubblica" e "privata", ma non protetta e protetta da pacchetti. Quindi lo esportate o "hardcoded" le chiamate. – Zed

+1

Ma perché non ho bisogno di esportare in caso di una chiamata vincolata staticamente xyz (Name) -> p(). e richiesto per esportare quando è associato dinamicamente? Pensando in termini di visibilità "privata", sono in ambito privato, no? – ottodidakt

0

Un altro modo di vedere le cose è che (a seconda del problema che stai solving) chiamate a funzioni dinamiche non è necessariamente la approccio corretto Dato che i processi e il passaggio dei messaggi sono il modo in cui organizzi il tuo codice in Erlang poiché si tratta di un "linguaggio orientato alla concorrenza", potresti semplicemente utilizzare il messaggio che passa con una ricezione selettiva anziché imitare gli idiomi di un linguaggio sequenziale? per quello che vuoi e ottenere la risposta personalizzata basata su di esso. Riguarda il risultato di ogni funzione, non la funzione stessa, dopo tutto. (Inoltre c'è la flessibilità e la scalabilità del messaggio che passa, ecc.)

Alt i processi di hush non sono completamente gratuiti rispetto alla chiamata da un modulo di libreria, i processi a livello di Erlang sono poco costosi (specialmente se la comunicazione del messaggio è all'interno dello stesso nodo). Non sono processi a livello di OS. Il sovraccarico sarebbe paragonabile (o migliore) alle chiamate a funzioni dinamiche e all'istanza degli oggetti nei linguaggi di script più pesanti.

1

Il modo più semplice è provare a esportare p e g insieme a xyz.

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

Dopo aver esportato la funzione p e g può essere chiamato come segue:

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