2009-02-17 14 views
40

me gustaría hacer algo como esto:¿Cómo se ejecutan varias instrucciones en una función anónima de MATLAB?

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

Así que cuando dije:

>> foo() 

Se ejecutaría functionCall1() y luego ejecutar functionCall2(). (Siento que necesito algo así como el C , operator)

EDIT:

functionCall1 y functionCall2 no son necesariamente las funciones que devuelven valores.

+0

¿Las funciones functionCall1 y functionCall2 alguna vez tienen que aceptar valores de entrada? De lo contrario, la solución que proporcioné a continuación debería funcionar. Si aceptan valores, mi solución podría funcionar pero necesitaría algunas modificaciones. – gnovice

+0

Actualicé mi respuesta con un ejemplo para pasar argumentos de entrada, en caso de que lo necesitara. – gnovice

Respuesta

45

Tratar de hacer todo a través de la línea de comandos sin guardar funciones en archivos-m puede ser un esfuerzo complicado y desordenado, pero aquí es una manera de que se me ocurrió ...

En primer lugar, hacer que su anonymous functions y ponen su handles en un cell array:

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

... o, si tiene funciones ya definidas (como en archivos-m), coloque la función maneja en una serie de células de este modo:

fcnArray = {@fcn1 @fcn2 @fcn3}; 

entonces puede presentar una nueva función anónima que llama a cada función en la matriz mediante las funciones cellfun y feval incorporadas:

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

Aunque de aspecto divertido, funciona.

EDIT: Si las funciones de fcnArray necesitan ser llamados con argumentos de entrada, primero tendría que asegurarse de que todas las funciones de la matriz requiere el mismo número de entradas. En ese caso, el siguiente ejemplo muestra cómo llamar a la matriz de funciones con un argumento de entrada cada uno:

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 


palabra de advertencia: La documentación para cellfun estados que el orden en el que la salida los elementos se computan no se especifica y no se debe confiar en ellos. Esto significa que no hay garantías de que fcn1 se evalúe antes de fcn2 o fcn3. Si el orden es importante, la solución anterior no debe usarse.

+0

dulce! He estado tratando de descubrir algo similar. –

+1

¡Interesante! Y, por supuesto, podría simplemente declarar fcnArray directamente en lugar de como una variable separada, por lo que algo como: 'myfun = @() cellfun (@feval, {@() xlim ([1 5]), @() xlabel (' segundos ')}); ' Ahora, al llamar a myfun establecerá xlim y xlabel en la figura. –

0

Tal vez me falta algo, solo haga una combinación de funciones Llamada que llame a ambas funciones por usted.

+0

bueno, espero poder hacerlo todo desde la ventana de comandos ... ¿sería posible? –

+0

Probablemente podría, ¿pero por qué molestarse? Use una secuencia de comandos y un archivo de función. Hace que sea más fácil iterar a través de su trabajo simplemente ejecutando el script del controlador. – MatlabDoug

11

La sintaxis de la función anónima en Matlab (como algunos otros idiomas) solo permite una sola expresión. Además, tiene una semántica de enlace variable diferente (las variables que no están en la lista de argumentos tienen sus valores vinculados léxicamente en el tiempo de creación de funciones, en lugar de enlazar las referencias). Esta simplicidad permite a Mathworks realizar algunas optimizaciones entre bastidores y evitar muchos problemas de alcance problemático y de duración de objetos al usarlos en scripts.

Si está definiendo esta función anónima dentro de una función (no una secuencia de comandos), puede crear funciones internas con nombre. Las funciones internas tienen un enlace de referencia léxico normal y permiten números arbitrarios de enunciados.

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

A veces se puede salir con trucos como la sugerencia de gnovice.

Tenga cuidado al usar eval ... es muy ineficiente (evita el JIT), y el optimizador de Matlab puede confundirse entre variables y funciones del alcance externo que se usan dentro de la expresión eval. También es difícil depurar y/o extender el código que usa eval.

1

Si functionCall1() y functionCall2() retorno algo y los veinteañeros se pueden concatenar, entonces usted puede hacer esto:

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

o

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

Un efecto secundario de esto es que foo() devolverá la concatenación de cualquier functionCall1() y functionCall2() devolución.

No sé si la orden de ejecución de functionCall1() y functionCall2() está garantizada.

+0

Sí, desafortunadamente estoy tratando con funciones que no devuelven valores. –

6

Aquí hay un método que garantizará el orden de ejecución y, (con las modificaciones mencionadas al final) permite pasar diferentes argumentos a diferentes funciones.

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

La clave es call1 que llama a su primer argumento y hace caso omiso de su segundo. call12 llama a su primer argumento y luego a su segundo, devolviendo el valor del segundo. Funciona porque una función no se puede evaluar antes de sus argumentos. Para crear su ejemplo, podría escribir:

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

Código de prueba

Aquí está el código de prueba utilicé:

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

llamadas más funciones

a llamar 3 funciones, puede escribir

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

4 funciones:

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

Para más funciones, siguen el patrón de anidación.

argumentos para el traspaso

Si necesita pasar argumentos, se puede escribir una versión de call1 que toma argumentos y luego hacer la modificación obvio para 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)) 

También puede crear versiones de call1 que tomen múltiples argumentos y los combinen según corresponda.

1

Es posible utilizar la función curly que se utiliza para crear una lista separada por comas.

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