Recursive Anonymous Function Matlab

Sé que esto no es para lo que están hechas las funciones anónimas, pero solo como un rompecabezas intenté hacer una función recursiva a través de funciones anónimas. El prototipo de funciones recursivas obviamente es la función factorial. El problema es que es difícil hacer una distinción de caso dentro de las funciones anónimas. Lo que logré hacer hasta ahora es lo siguiente:

f=@(cn,n,f)eval('if n>1; f(cn*n,n-1,f);else;ans=cn;end'); f=@(n)f(1,n,f); 

O alternativamente:

 f=@(cn,n,f)eval('if n>1; f(cn*n,n-1,f);else;disp(cn);end'); f=@(n)f(1,n,f); 

Lo que no es muy satisfactorio es que aún no puede usar esta función cuando asigna directamente, a=f(3) aún produce un error, ya que eval no obtiene un valor.

Entonces mi pregunta es, ¿pueden realmente hacer una función recursiva a través de funciones anónimas que, por ejemplo, calcula factorial de una manera que permite, por ejemplo, a=f(3) confiar únicamente en funciones de matlab nativas (o funciones que puede crear en la línea de comando, como Lo hice en mi ejemplo)?

PD: Sé que esto no tiene ningún uso práctico, es solo un desafío sobre cuánto puedes doblar y abusar de la syntax de Matlab.

Encontramos dos posibilidades ahora, ambas dependen del uso de matrices de células. Tenga en cuenta que esto podría no funcionar en Octave.

La clave fue la implementación de una distinción de caso. El primero que encontré, se puede encontrar aquí.

Este método hace uso de los valores boleanos de matlabs, true se puede evaluar como 1 mientras que falso se puede evaluar como 0 .

 if_ = @( pred_, cond_ ) cond_{ 2 - pred_ }(); 

Aquí tenemos que proporcionar una condición como primer argumento, y una matriz de celdas de 2 elementos como segundo argumento. Cada elemento de celda debe ser un identificador de función que se llama si la condición es verdadera / no verdadera. Nuestra función factorial se vería así:

 fac = @(n,f)if_(n>1,{@()n*f(n-1,f),@()1}) factorial_=@(n)fac(n,fac); factorial_(10) 

Como @AndrasDeak comentó a continuación: La parte importante aquí es que tenemos una matriz de funciones y no de valores . Esto proporciona el cortocircuito, ya que n*f(n-1,f) no se evalúa a menos que llamemos a la función correspondiente @()n*f(n-1,f) .

El segundo método fue encontrado por @beaker y es algo más flexible:

 iif = @(varargin) varargin{2*find([varargin{1:2:end}], 1, 'first')}(); 

Esto hace uso del hecho de que puede usar varargin (cantidad variable de argumentos) incluso en funciones anónimas. Cuando llamas a esta función, tienes que alternar las condiciones y lo que se debe ejecutar si la condición es verdadera. Este incluso permite una construcción de switch , o if ... else if ... else if ... (...) else ... construye. Cuando se llame, buscará la primera condición que sea verdadera ( find([varargin{1:2:end}], 1, 'first') ) y llamará a la función correspondiente. Nuestro ejemplo de la función factorial se ve así:

 fac = @(n,f)iif(n>1,@()n * f(n-1,f),true,@()1); factorial_=@(n)fac(n,fac); factorial_(10) 

EDITAR: Dato curioso: lo que estamos haciendo con la línea

  factorial_=@(n)fac(n,fac); 

también se conoce como aplicar el Y-combinator . De hecho, podemos escribir eso como

  Y = @(f)@(x)f(x,f); factorial_=Y(f); 
    Intereting Posts