2009-08-21 12 views
13

Je veux appeler xyz avec le nom d'une fonction à appeler.Dans Erlang, comment appelez-vous dynamiquement une fonction?

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

xyz(Name) -> Name(). 

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

Mais je reçois l'erreur suivante:

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

Ma connaissance Erlang est proche de zéro, mais je suppose que vous devez exporter p (et éventuellement g, si vous voulez pour l'utiliser). – balpha

Répondre

22

Il est exact que vous devez exporter p et g. Vous pouvez ensuite utiliser apply/3 pour l'appeler.

erlang:apply(sample, p, []) 

Seules les valeurs amusantes sont utilisables avec la syntaxe Fun (...). Vous passez dans une valeur d'atome. Un atome est une «mauvaise fonction» comme le message d'erreur va. Vous pourriez faire quelque chose de similaire à

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

Alors allez-y et appelez

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

Merci. J'ai maintenant ceci: -module (échantillon). -export ([xyz/1, p/0, g/0]). xyz (Nom) -> appliquer (exemple, nom, []). p() -> "vous avez appelé p". g() -> "vous avez appelé g". et je suis capable de faire: 26> c (sample.erl). {ok, sample} 27> échantillon: xyz ('p'). "vous avez appelé p" 28> échantillon: xyz (p). "vous avez appelé p" 29> échantillon: xyz ('g'). "vous avez appelé g" 30> échantillon: xyz (g). "vous avez appelé g" Mais n'y a-t-il pas moyen de ne pas exporter ces fonctions? Je ne veux pas qu'il soit visible par les utilisateurs du module. Je n'arrive pas à l'utiliser avec apply/2 non plus. Bien sûr, je suis un erlang newbie – ottodidakt

+1

Vous pouvez coder en dur votre mappage d'appel avec correspondance de motif, ou exporter vos fonctions. – Zed

+0

La seule façon de 'fuir' une fonction non exportée est de retourner une valeur amusante qui s'y réfère. Tout comme ma fonction xyz/1 explicite qui renvoie une valeur amusante. – Christian

7

match de modèle est l'idiome à utiliser:

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

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

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

Si vous voulez être dynamique, vous pouvez utiliser un gen_event serveur.

Essentiellement ce que c'est est un serveur qui contient un état qui se compose de paire de clés/fonction comme ceci:

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

Vous pouvez ensuite lier essentiellement des événements à des fonctions. (Il est inutile de dire, un peu plus que ça.

+1

alors que c'est techniquement une façon de le faire, je pense que la question est plus axée sur la mécanique dans erlang le langage pour appeler dynamiquement une fonction. La fonction apply est la réponse qu'il cherche. –

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

C'est plutôt cool. Où puis-je lire sur "? MODULE"? Maintenant, si seulement nous pouvions faire l'exportation de p et q. – ottodidakt

+0

Voici les macros prédéfinies: http://erlang.org/doc/reference_manual/macros.html#7.3. Malheureusement, Erlang n'a qu'une visibilité "publique" et "privée", mais aucune protection et paquet protégé. Donc, soit vous l'exportez, soit vous «codez» les appels. – Zed

+1

Mais pourquoi ne suis-je pas obligé d'exporter dans le cas d'un appel lié statiquement xyz (Name) -> p(). et requis pour exporter quand il est lié dynamiquement? En pensant en termes de visibilité "privée", je suis dans le domaine privé, n'est-ce pas? – ottodidakt

0

Une autre façon de regarder est que (en fonction du problème que vous résolvez) des appels dynamiques à des fonctions ne sont pas nécessairement la Comme les processus et le passage des messages sont la façon dont vous organisez votre code dans Erlang puisqu'il s'agit d'un "langage orienté vers la concurrence", peut-être pourriez-vous simplement utiliser le passage de message avec une réception sélective plutôt que d'imiter un idiome séquentiel? Pour ce que vous voulez et obtenir la réponse personnalisée basée sur cela.Il s'agit du résultat de chaque fonction, pas la fonction elle-même, après tout. (Plus il ya la flexibilité et l'évolutivité du passage des messages, etc.)

Alt Les processus non significatifs ne sont pas totalement gratuits par rapport à l'appel d'un module de bibliothèque, les processus au niveau d'Erlang sont peu coûteux (surtout si la communication de messages se fait dans le même nœud). Ce ne sont pas des processus au niveau du système d'exploitation. La surcharge serait comparable (ou meilleure) aux appels de fonctions dynamiques et à l'instanciation d'objets dans des langages de script plus lourds.

1

Le plus simple est d'essayer d'exporter p et g avec xyz.

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

Après avoir exporté la fonction p et g peut être appelé comme suit:

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