2015-08-26 35 views
11

So che questo non è ciò che le funzioni anonime sono fatte per, ma proprio come un puzzle ho provato a fare una funzione ricorsiva tramite funzioni anonime. Il prototipo delle funzioni ricorsive è ovviamente la funzione fattoriale. Il problema è che è difficile distinguere il caso all'interno delle funzioni anonime entro. Quello che sono riuscito a fare finora è la seguente:Funzione anonima ricorsiva Matlab

[email protected](cn,n,f)eval('if n>1; f(cn*n,n-1,f);else;ans=cn;end'); 
[email protected](n)f(1,n,f); 

O in alternativa:

[email protected](cn,n,f)eval('if n>1; f(cn*n,n-1,f);else;disp(cn);end'); 
[email protected](n)f(1,n,f); 

Ciò che non è molto soddisfacente è che ancora non è possibile utilizzare questa funzione quando si assegna direttamente, a=f(3) produce ancora un errore, dal eval non si ottiene un valore.

Quindi la mia domanda è: puoi effettivamente eseguire una funzione ricorsiva tramite funzioni anonime che, ad es. calcola fattoriale in un modo che consente ad es. a=f(3) affidandosi solo a funzioni matlab native (o funzioni che è possibile creare nella riga di comando, come ho fatto nel mio esempio)?

PS: So che questo non ha alcun uso pratico, è solo una sfida su quanto si può piegare e abusare della sintassi di Matlab.

+0

Intendi funzione anonima? La maniglia della funzione sembra essere una classe di oggetti più ampia per me. Ma non sono un esperto, quindi lo sto davvero chiedendo. –

+0

@AndrasDeak Certo che sì, grazie per averlo sottolineato! – flawr

+0

Nessun accesso Matlab al momento, ma hai provato a fare qualcosa di simile a questo '' if n> 1; f (CN * n, n-1, f); altro; cn; FINE'? – patrik

risposta

5

Abbiamo trovato due possibilità ora, entrambe si basano sull'uso di matrici di celle. Si noti che questo potrebbe non funzionare in Octave.

La chiave era un'implementazione di una distinzione tra maiuscole e minuscole. Il primo che ho trovato, può essere trovato here.

Questo metodo si avvale di matlabs valori booleani, vero può essere valutata come 1 mentre falso può essere valutata come 0.

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

Qui dobbiamo fornire una condizione come primo argomento e un array di celle a 2 elementi come secondo argomento. Ogni elemento di cella dovrebbe essere un handle di funzione che viene chiamato se la condizione è vera/non vera. La nostra funzione fattoriale sarebbe simile a questa:

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

Come @AndrasDeak commentato di seguito: La parte importante qui è che abbiamo un array di celle di funzioni e non di valori. Ciò fornisce il cortocircuito, poiché n*f(n-1,f) non viene valutato a meno che non si chiami la funzione corrispondente @()n*f(n-1,f).

Il second method è stato trovato da @beaker ed è un po 'più flessibile:

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

Questo fa uso del fatto che è possibile utilizzare varargin (importo variabile di argomenti), anche nelle funzioni anonime. Quando chiami questa funzione devi alternare le condizioni e cosa dovrebbe essere eseguito se la condizione è vera. Questo permette anche un costrutto switch o un costrutto if ... else if ... else if ... (...) else .... Quando chiamato, cercherà la prima condizione vera (find([varargin{1:2:end}], 1, 'first')) e richiamerà la funzione corrispondente.Il nostro esempio della funzione fattoriale è simile al seguente:

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

EDIT: Una curiosità: Quello che stiamo facendo con la linea

[email protected](n)fac(n,fac); 

è anche conosciuto come l'applicazione del Y-combinator. Infatti possiamo scrivere che come

Y = @(f)@(x)f(x,f); 
factorial_=Y(f); 
+1

Suggerisco di enfatizzare in entrambi i casi che '@()' è necessario per proteggere l'argomento dalla valutazione. Da quando chiamate, per esempio, 'mean (rand (3))', matlab prima valuta 'rand (3)', quindi passa quella matrice alla funzione 'mean'. Se si omettere la parte '@()', 'iif' proverebbe a valutare la funzione priva di significato. Punto principale: la funzione 'iif' sembra cortocircuitare al primo argomento' true', ma non lo fa. –