43 votes

Comment exécuter plusieurs instructions dans une fonction anonyme MATLAB ?

J'aimerais faire quelque chose comme ça :

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

Donc, quand j'ai dit :

>> foo()

Il exécuterait functionCall1() et ensuite exécuter functionCall2() . (Je sens que j'ai besoin de quelque chose comme le C , opérateur )

EDITAR:

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

45voto

gnovice Points 70970

Essayer de tout faire via la ligne de commande sans sauvegarder les fonctions dans des m-files peut être une entreprise compliquée et désordonnée, mais voici une méthode que j'ai trouvée...

D'abord, faites votre fonctions anonymes et mettre leur poignées dans un réseau de cellules :

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

...ou, si vous avez des fonctions déjà définies (comme dans les fichiers m), placez les poignées des fonctions dans un tableau de cellules comme ceci :

fcnArray = {@fcn1 @fcn2 @fcn3};

Vous pouvez ensuite créer une nouvelle fonction anonyme qui appelle chaque fonction du tableau à l'aide des fonctions intégrées. cellfun y feval :

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

Bien que d'apparence bizarre, ça fonctionne.

EDITAR: Si les fonctions de fcnArray doivent être appelées avec des arguments d'entrée, vous devez d'abord vous assurer que TOUTES les fonctions du tableau nécessitent le même nombre d'entrées. Dans ce cas, l'exemple suivant montre comment appeler le tableau de fonctions avec un argument d'entrée chacune :

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

UN MOT D'AVERTISSEMENT : La documentation pour cellfun indique que le commander dans laquelle les éléments de sortie sont calculés n'est pas spécifiée et ne doit pas être invoquée. Cela signifie qu'il n'y a aucune garantie que fcn1 est évalué avant fcn2 o fcn3 . Si l'ordre est important, la solution ci-dessus ne devrait pas être utilisée.

13voto

Mr Fooz Points 21092

La syntaxe des fonctions anonymes dans Matlab (comme dans certains autres langages) ne permet qu'une seule expression. De plus, elle a une sémantique de liaison de variables différente (les variables qui ne sont pas dans la liste d'arguments ont leur nom dans la liste des variables). valeurs liés 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 quelques optimisations en coulisse et d'éviter de nombreux problèmes de scoping et de durée de vie des objets lors de leur utilisation dans des scripts.

Si vous définissez cette fonction anonyme à l'intérieur d'une fonction (pas un script), vous pouvez créer des fonctions internes nommées. Les fonctions internes ont une liaison de référence lexicale normale et permettent un nombre arbitraire d'instructions.

function F = createfcn(a,...)
  F = @myfunc;
  function b = myfunc(...)
    a = a+1; 
    b = a; 
  end
end

Parfois, on peut s'en sortir avec des astuces comme la suggestion de gnovice.

Faites attention à l'utilisation de eval... c'est très inefficace (il contourne le JIT), et l'optimiseur de Matlab peut se tromper entre les variables et les fonctions de la portée externe qui sont utilisées à l'intérieur de l'expression eval. Il est également difficile de déboguer et/ou d'étendre le code qui utilise eval.

6voto

Eponymous Points 577

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

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

La clé est call1 qui appelle son premier argument et ignore son second. call12 appelle son premier argument, puis son second, et renvoie la valeur du second. Cela fonctionne car une fonction ne peut pas être évaluée avant ses arguments. Pour créer votre exemple, vous devez écrire :

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

Code d'essai

Voici le code de test que j'ai utilisé :

>> print1=@()fprintf('1\n');
>> print2=@()fprintf('2\n');
>> call12(print1,print2)
1
2

Appeler d'autres fonctions

Pour appeler 3 fonctions, vous pourriez écrire

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

4 fonctions :

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

Pour plus de fonctions, continuez le schéma d'imbrication.

Passage d'arguments

Si vous avez besoin de passer des arguments, vous pouvez écrire une version de call1 qui prend des arguments et ensuite faire 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 comme il convient.

1voto

ManWithSleeve Points 1409

Si functionCall1() y functionCall2() renvoie quelque chose et que ces choses peuvent être concaténées, alors vous pouvez faire ceci :

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

ou

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

Un effet secondaire de ceci est que foo() retournera la concaténation de ce que functionCall1() y functionCall2() retour.

Je ne sais pas si l'ordre d'exécution de functionCall1() y functionCall2() est garanti.

0voto

MatlabDoug Points 4587

Peut-être que j'ai raté quelque chose, faites simplement une fonction combinationCall qui appelle les deux fonctions pour vous.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X