2009-08-21 8 views
13

Ich möchte XYZ mit dem Namen einer Funktion aufrufen, die aufgerufen werden soll.In Erlang, wie rufen Sie eine Funktion dynamisch auf?

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

xyz(Name) -> Name(). 

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

Aber ich erhalte den folgenden Fehler:

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

Mein Erlang Wissen nahe bei Null liegt, aber ich nehme an, Sie haben p (und möglicherweise g exportieren, wenn Sie möchten, um es zu benutzen). – balpha

Antwort

22

Es ist richtig, dass Sie p und g zu exportieren haben. Sie können dann apply/3 verwenden, um es aufzurufen.

erlang:apply(sample, p, []) 

Nur Fun-Werte sind mit der Fun (...) Syntax verwendbar. Sie übergeben einen Atomwert. Ein Atom ist eine "schlechte Funktion" als die Fehlermeldung gehen. Sie könnten dann weiter und

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

Danke. Ich habe jetzt das: -Modul (Beispiel). -export ([xyz/1, p/0, g/0]). xyz (Name) -> anwenden (Beispiel, Name, []). p() -> "Sie haben p angerufen". g() -> "Sie haben g angerufen". und ich bin in der Lage zu tun: 26> c (sample.erl). {ok, Probe} 27> Beispiel: xyz ('p'). "Sie riefen p" 28> Beispiel: xyz (p). "Sie haben p" 29> Beispiel: xyz ('g'). "Sie riefen g" 30> Probe: xyz (g). "Sie riefen g" Aber gibt es keine Möglichkeit, diese Funktionen nicht zu exportieren? Ich möchte nicht, dass es für Modulbenutzer sichtbar ist. Es scheint auch nicht zu funktionieren mit apply/2. Natürlich bin ich ein Erlang-Neuling. – ottodidakt

+1

Entweder programmieren Sie Ihre Call-Mapping mit Mustererkennung, oder exportieren Sie Ihre Funktionen. – Zed

+0

Die einzige Möglichkeit, eine nicht exportierte Funktion zu "lecken", besteht darin, einen Fun-Wert zurückzugeben, der darauf verweist. Genau wie meine explizite xyz/1-Funktion, die einen lustigen Wert zurückgibt. – Christian

7

Pattern Match das Idiom nennen gehen etwas ähnliches wie

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

tun ist, zu verwenden:

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

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

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

Wenn Sie dynamisch sein möchten, können Sie ein verwenden gen_event Server.

Im Wesentlichen das, was ist, ist ein Server, der einen Zustand, der wie so besteht aus Schlüssel/Funktionspaar hält:

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

Sie können dann im wesentlichen Ereignisse an Funktionen binden. (Es ist, unnötig zu sagen, ein bisschen mehr als das.

+1

während dies technisch eine Möglichkeit ist, es zu tun, denke ich, die Frage ist mehr auf die Mechanik in Erlang die Sprache ausgerichtet, um eine Funktion dynamisch aufzurufen. Die Anwendungsfunktion ist die Antwort, nach der er sucht. –

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

Das ist ziemlich cool. Wo kann ich über "MODUL" nachlesen? Wenn wir jetzt nur noch p und q exportieren könnten. – ottodidakt

+0

Hier sind die vordefinierten Makros: http://erlang.org/doc/reference_manual/macros.html#7.3. Leider hat Erlang nur "öffentliche" und "private" Sichtbarkeit, aber keine geschützten und paketgeschützten. So exportieren Sie es entweder oder "hardcodieren" Sie die Anrufe. – Zed

+1

Aber warum muss ich im Falle eines statisch gebundenen Aufrufs nicht exportieren xyz (Name) -> p(). und muss exportiert werden, wenn es dynamisch gebunden ist? Ich denke in Bezug auf "private" Sichtbarkeit, ich bin privat, nicht wahr? – ottodidakt

0

Ein anderer Weg, um es zu betrachten, dass (je nach Problem, das Sie lösen) dynamische Aufrufe von Funktionen ist nicht unbedingt die Angesichts der Tatsache, dass Prozesse und Nachrichtenübergabe die Art und Weise sind, wie Sie Ihren Code in Erlang organisieren, da es sich um eine "Nebenläufigkeits-orientierte Sprache" handelt, könnten Sie Nachrichtenübermittlung mit selektivem Empfang verwenden, anstatt idiomatische Ausdrücke einer sequentiellen Sprache nachzuahmen für was Sie wollen und erhalten Sie die benutzerdefinierte Antwort basierend auf das. Es ist über das Ergebnis jeder Funktion, nicht die Funktion selbst. (Und es gibt die Flexibilität und Skalierbarkeit der Nachrichtenübergabe, etc.)

Alt Wenn Prozesse nicht völlig frei sind im Vergleich zum Aufruf von einem Bibliotheksmodul, sind Prozesse auf Erlang-Ebene spottbillig (insbesondere wenn die Nachrichtenkommunikation innerhalb desselben Knotens stattfindet). Sie sind keine Prozesse auf Betriebssystemebene. Der Overhead wäre vergleichbar mit (oder besser) dynamischen Funktionsaufrufen und Objekt-Instanziierung in schwereren Skriptsprachen.

1

Der einfachste Weg ist, zu versuchen, p und g zusammen mit xyz zu exportieren.

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

Nach dem Export der Funktion p und g kann wie folgt aufgerufen werden:

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