3. února 2011

Currying

Čtu teď knížku Groovy for Domain-Specific Languages a zaujala mě tam technika, kterou jsem doposud neznal - currying. V krátkosti jde o transformaci funkce, která má více argumentů (nebo pole argumentů) tak, že může být zavolána jako řetěz funkcí s jedním argumentem. Zapsáno matematicky: g(y) = (y -> f(x,y)). Funkce g je "(z)kariovaná"  (curried) verze funkce f.
Pojem currying je spojován hlavně se jménem matematika Haskella Curryho. Ano, je to ten Haskell, po kterém je pojmenován (čistě) funkcionální jazyk Haskell. Currying je vlastní v podstatě všem funkcionálním jazykům, za zmínku stojí speciálně Haskell a ML, kde všechny funkce mají přesně jeden argument, tj. jsou "kariované". "Kariované" funkce by také měly jít použít/vytvořit ve všech jazycích, které podporují closures, namátkou:
No a jak vypadá currying konkrétně? V Groovy:
def spicy = { first, second, third ->
  println "I like food with $first, $second and $third."
}

def curry = spicy.curry("curry")
def moreCurry = curry.curry("curry")
def curryAndChilli = moreCurry.curry("chilli")

curryAndChilli.call()
// prints:
// I like food with curry, curry and chilli.
No a tenhle blog je o Clojure, takže jak to vypadá v Clojure?
(defn spicy [first second third]
  (println "I like food with"
           first "," second "and" third "."))
(def curry (partial spicy "curry"))
(def more-curry (partial curry "curry"))
(def curry-and-chilli (partial more-curry "chilli"))
(curry-and-chilli)
; I like food with curry , curry and chilli .
V Clojure není potřeba syslit argumenty po jednom, ale dá se jich zadat víc naráz (1-n):
(defn spicy [first second third]
  (println "I like food with"
           first "," second "and" third "."))
(def curry-and-chilli
  (partial spicy "curry" "curry" "chilli"))
(curry-and-chilli)
; I like food with curry , curry and chilli .
Závěrem, k čemu je vlastně currying dobrý? Kromě toho, že může zpřehlednit/zjednodušit funkce s mnoha argumenty (lambda kalkul v matematice), je hlavní výhoda použití v doplňování argumentů on-the-fly - doplním argumenty, které aktuálně znám a ostatní doplním, až budou k dispozici. Vzhledem k tomu, že Clojure je lazy-init, může být currying konvenující metoda.

Žádné komentáře:

Okomentovat