Currying

Vedi tutte le pagine e le modifiche recenti o scarica i sorgenti nella pagina


Il currying e’ un meccanismo molto curioso pensato da un matematico d nome Haskell Curry. In pratica si tratta di un’applicazione parziale di una funzione che genera un’altra funzione. O del pensare ad ogni funzione come una funzione che accetta un solo argomento, e ne restituisce generalmente un’altra.

Vi sembra difficile? non lo e’, tranquilli :) Ad esempio, se io ho una funzione somma(arg1,arg2 posso effettuare il currying tra la funzione ed un solo valore , ed ottenere una funzione che accetti un solo valore ad un altro.

Ad esempio, in ocaml, un linguaggio funzionale che ha il currying automatico, scriverei:

* dichiarazione della funzione:
 let somma arg1 arg2 = arg1+arg2 ;;  
* creiamo la funzione incompleta, effettuando il currying automatico:
 let somma_due  = somma 2 ;;
* usiamo la funzione:
 somma_due 10 ;;
 - : int = 12

L’ultima riga sarebbe il risultato, 12.

Pochi linguaggi hanno un sistema di currying automatico, ma in linguaggi come ruby che danno la possibilita’ di manipolare funzioni e crearle “al volo” e’ semplice realizzare una funzione curry() che prenda in input una funzione e dei valori:
 def curry(funz, *alcuni_arg)
     proc { |*altri_arg| funz[*(alcuni_arg + altri_arg)] }
 end

cosa facciamo in quel casino?

andiamo per gradi: # la funzione prende in input un oggetto funzione (Proc o Method) e degli argomenti di default. # all’interno della funzione viene generata una FormaLambda? # la funzione anonima richiama tramite l’operatore “[]” la funzione ricevuta in input # gli argomenti passati alla funzione in input sono quelli passato alla funzione curry() piu’ quelli passati effettivamente all’oggetto Proc. Questi argomenti sono Array che vengono prima sommati tra loro (cioe’ concatenati) e poi espansi grazie alla sintassi *(Array)

Vediamo la nostra funzione all’opera:
 >>  def curry(funz, *alcuni_arg)
 >>      proc { |*altri_arg| funz[*(alcuni_arg + altri_arg)] }
 >>  end
 => nil
 >> def somma(arg1,arg2) arg1+arg2 end
 => nil
 >> s=method :somma
 => #<Method: Object#somma>
 >> somma_2 = curry(s, 2)
 => #<Proc:0x027be8e0@(irb):53>
 >> somma_2[10]
 => 12

Volendo avremmo potuto far si che curry() prendesse in input solamente il simbolo di una funzione, ma questa e’ una soluzione lasciata al lettore :)

Guardate quest’ultimo esempio: curry() funziona per tutti gli argomenti che vogliamo
 >> def somma_5(a1,a2,a3,a4,a5) a1+a2+a3+a4+a5 end
 => nil
 >> s=method :somma_5
 => #<Method: Object#somma_5>
 >> somma_4_e_1 =curry s, 1
 => #<Proc:0x027be8e0@(irb):53>
 >> somma_4_e_1[2,3,4,5]
 => 15
 >> somma_1_e_4 =curry s, 1, 2,3,4
 => #<Proc:0x027be8e0@(irb):53>
 >> somma_1_e_4[5]
 => 15
Updated on November 25, 2005 14:36 by il gruppo (127.0.0.1)