2009-02-17 12 views
40

Je voudrais faire quelque chose comme ceci:Comment exécuter plusieurs instructions dans une fonction anonyme MATLAB?

>> foo = @() functionCall1() functionCall2() 

Alors que quand je l'ai dit:

>> foo() 

Il exécuterait functionCall1() puis exécutez functionCall2(). (Je sens que je besoin de quelque chose comme le C , operator)

EDIT:

functionCall1 et functionCall2 ne sont pas nécessairement des fonctions qui renvoient des valeurs.

+0

Est-ce que functionCall1 et functionCall2 doivent accepter des valeurs d'entrée? Sinon, la solution que j'ai donnée ci-dessous devrait fonctionner. S'ils acceptent les valeurs, ma solution pourrait fonctionner mais nécessiterait quelques modifications. – gnovice

+0

J'ai mis à jour ma réponse avec un exemple pour passer des arguments d'entrée, juste au cas où vous en auriez besoin. – gnovice

Répondre

45

Essayer de tout faire via la ligne de commande sans fonctions enregistrement dans les fichiers m-peut être une entreprise complexe et désordonné, mais voici une façon que je suis venu avec ...

Tout d'abord, faites votre anonymous functions et mettre leur handles dans un cell array:

fcn1 = @() ...; 
fcn2 = @() ...; 
fcn3 = @() ...; 
fcnArray = {fcn1 fcn2 fcn3}; 

... ou, si vous avez des fonctions déjà définies (comme dans les fichiers m-), placez la fonction poignées dans une matrice de cellules comme ceci:

fcnArray = {@fcn1 @fcn2 @fcn3}; 

Ensuite, vous pouvez faire une nouvelle fonction anonyme qui appelle chaque fonction dans le tableau en utilisant les fonctions intégrées cellfun et feval:

foo = @() cellfun(@feval,fcnArray); 

Bien drôle de, cela fonctionne.

EDIT: Si les fonctions fcnArray doivent être appelés avec des arguments d'entrée, vous faudrait d'abord faire en sorte que toutes les fonctions du tableau exigent que le même nombre d'entrées. Dans ce cas, l'exemple suivant montre comment appeler l'ensemble des fonctions avec un argument d'entrée chacun:

foo = @(x) cellfun(@feval,fcnArray,x); 
inArgs = {1 'a' [1 2 3]}; 
foo(inArgs); %# Passes 1 to fcn1, 'a' to fcn2, and [1 2 3] to fcn3 


MOT DE MISE EN GARDE: La documentation cellfun indique que le ordre dans lequel la sortie Les éléments calculés ne sont pas spécifiés et ne doivent pas être utilisés. Cela signifie qu'il n'y a aucune garantie que fcn1 est évalué avant fcn2 ou fcn3. Si l'ordre est important, la solution ci-dessus ne doit pas être utilisée.

+0

doux! J'ai essayé de trouver quelque chose de similaire. –

+1

Intéressant! Et bien sûr, vous pouvez simplement déclarer fcnArray directement en tant que variable séparée, donc quelque chose comme: 'myfun = @() cellfun (@feval, {@() xlim ([1 5]), @() xlabel (' secondes ')}); ' Maintenant, l'appel de myfun va mettre xlim et xlabel dans la figure. –

0

Peut-être que je suis manquant somethign, il suffit de faire une combinaison de fonctionAppel qui appelle les deux fonctions pour vous.

+0

Eh bien, j'espère être en mesure de tout faire à partir de la fenêtre de commande ... serait-ce possible? –

+0

Vous pourriez probablement, mais pourquoi s'embêter? Utilisez un script et un fichier de fonction. Il est plus facile de parcourir votre travail en exécutant simplement le script du pilote. – MatlabDoug

11

La syntaxe de fonction anonyme dans Matlab (comme d'autres langages) n'autorise qu'une seule expression. De plus, il a différentes sémantiques de liaison de variables (les variables qui ne sont pas dans la liste d'arguments ont leurs valeurs liées lexicalement au moment de la création de la fonction, au lieu que les références soient liées). Cette simplicité permet à Mathworks d'effectuer des optimisations en coulisse et d'éviter de nombreux problèmes de portée et de durée de vie des objets lors de leur utilisation dans les scripts.

Si vous définissez cette fonction anonyme dans une fonction (pas un script), vous pouvez créer des fonctions internes du nom. Les fonctions internes ont une liaison de référence lexicale normale et autorisent un nombre arbitraire d'instructions. Parfois, vous pouvez vous échapper avec des astuces comme la suggestion de gnovice. Faites attention à l'utilisation d'eval ... c'est très inefficace (il contourne le JIT), et l'optimiseur de Matlab peut se confondre entre les variables et les fonctions de la portée externe qui sont utilisées dans l'expression eval. Il est également difficile de déboguer et/ou d'étendre le code qui utilise eval.

1

Si functionCall1() et functionCall2() retour quelque chose et ces somethings peuvent être concaténés, vous pouvez le faire:

>> foo = @() [functionCall1(), functionCall2()]

ou

>> foo = @() [functionCall1(); functionCall2()]

Un effet secondaire est que foo() retourne la concaténation de tout functionCall1() et functionCall2() retour. Je ne sais pas si l'ordre d'exécution functionCall1() et functionCall2() est garanti.

+0

Oui, malheureusement, j'ai affaire à des fonctions qui ne renvoient pas de valeurs. –

6

Voici une méthode qui garantira l'ordre d'exécution et, (avec des modifications mentionnées à la fin) permet de passer des arguments différents pour les différentes fonctions.

call1 = @(a,b) a(); 
call12 = @(a,b) call1(b,call1(a,b)); 

La clé est call1 qui appelle son premier argument et ne tient pas compte de son second. call12 appelle son premier argument, puis son second, renvoyant la valeur de la seconde. Cela fonctionne parce qu'une fonction ne peut pas être évaluée avant ses arguments. Pour créer votre exemple, vous écrivez:

foo = @() call12(functionCall1, functionCall2); 

Code d'essai

Voici le code de test je:

>> [email protected]()fprintf('1\n'); 
>> [email protected]()fprintf('2\n'); 
>> call12(print1,print2) 
1 
2 

Appel plus de fonctions

Pour appeler 3 fonctions, vous pouvez écrire

call1(print3, call1(print2, call1(print1,print2))); 

4 fonctions:

call1(print4, call1(print3, call1(print2, call1(print1,print2)))); 

Pour plus de fonctions, continuent le modèle d'imbrication.

Arguments Passing

Si vous avez besoin de passer des arguments, vous pouvez écrire une version de call1 qui prend des arguments et rendre la modification évidente call12.

call1arg1 = @(a,arg_a,b) a(arg_a); 
call12arg1 = @(a, arg_a, b, arg_b) call1arg1(b, arg_b, call1arg1(a, arg_a, b)) 

Vous pouvez également créer des versions de call1 qui prennent plusieurs arguments et les mélanger le cas échéant.

1

Il est possible d'utiliser la fonction curly qui est utilisée pour créer une liste séparée par des virgules.

curly = @(x, varargin) x{varargin{:}}; 
[email protected](x)curly({exp(x),log(x)}) 
[a,b]=f(2) 
Questions connexes