Pensando funcionalmente

  • 91 views
Uploaded on

Una intro a los beneficios de la programación funcional, con breves ejemplos en Python, Ruby y Clojure.

Una intro a los beneficios de la programación funcional, con breves ejemplos en Python, Ruby y Clojure.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
91
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
0
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Pensando FuncionalmentePensando Funcionalmente Denis Fuenzalida – Agosto de 2013Denis Fuenzalida – Agosto de 2013 denis.fuenzalida@gmail.comdenis.fuenzalida@gmail.com
  • 2. Programación funcional?Programación funcional?
  • 3. •• Problema: no hay definiciónProblema: no hay definición universalmenteuniversalmente aceptadaaceptada •• Funciones como elementos de primer nivel del lenguaje:Funciones como elementos de primer nivel del lenguaje: ““First Class FunctionsFirst Class Functions”” →→ es posible almacenares posible almacenar referenciasreferencias a funcionesa funciones pasar funciones como→pasar funciones como→ parámetrosparámetros →→ crear funciones que retornancrear funciones que retornan funcionesfunciones DefiniciónDefinición
  • 4. •• Mayor nivel de abstracción:Mayor nivel de abstracción: más énfasis en el→más énfasis en el→ quéqué y no en ely no en el cómocómo →→ menos código que comprendermenos código que comprender →→ a veces, código más genérico y re-utilizablea veces, código más genérico y re-utilizable •• EnEn ClojureClojure se prefieren funciones puras*se prefieren funciones puras* son más fáciles de entender→son más fáciles de entender→ →→ más fáciles de testearmás fáciles de testear →→ se pueden guardarse pueden guardar en cachéen caché y paralelizary paralelizar fácilmentefácilmente BeneficiosBeneficios
  • 5. Convertir de códigoConvertir de código imperativo a funcionalimperativo a funcional
  • 6. // Basado en StringUtils.java de Apache Commons Lang// Basado en StringUtils.java de Apache Commons Lang /*/* * Spec:* Spec: ** * StringUtils.indexOfAny(null, *) = -1* StringUtils.indexOfAny(null, *) = -1 * StringUtils.indexOfAny("", *) = -1* StringUtils.indexOfAny("", *) = -1 * StringUtils.indexOfAny(*, null) = -1* StringUtils.indexOfAny(*, null) = -1 * StringUtils.indexOfAny(*, []) = -1* StringUtils.indexOfAny(*, []) = -1 * StringUtils.indexOfAny("* StringUtils.indexOfAny("zzzabyycdxx",['z','a']) = 0zabyycdxx",['z','a']) = 0 * StringUtils.indexOfAny("zza* StringUtils.indexOfAny("zzabbyycdxx",['b','y']) = 3yycdxx",['b','y']) = 3 * StringUtils.indexOfAny("aba", ['z']) = -1* StringUtils.indexOfAny("aba", ['z']) = -1 */*/
  • 7. // Basado en StringUtils.java de Apache Commons Lang// Basado en StringUtils.java de Apache Commons Lang classclass StringUtils {StringUtils { public staticpublic static intint indexOfAnyindexOfAny(String(String strstr, char[], char[] toSearchtoSearch){){ ifif (isEmpty(str) || ArrayUtils.isEmpty(toSearch)){(isEmpty(str) || ArrayUtils.isEmpty(toSearch)){ returnreturn -1;-1; }} forfor (int i = 0; i < str.length(); i++){(int i = 0; i < str.length(); i++){ charchar chch = str.charAt(i);= str.charAt(i); forfor (int(int jj = 0; j < toSearch.length; j++){= 0; j < toSearch.length; j++){ ifif (searchChars[j] == ch){(searchChars[j] == ch){ returnreturn i;i; }} }} }} returnreturn -1;-1; }} }}
  • 8. // Simplificando condiciones de borde...// Simplificando condiciones de borde... classclass StringUtils {StringUtils { public staticpublic static intint indexOfAnyindexOfAny(String(String strstr, char[], char[] toSearchtoSearch){){ when (toSearch) {when (toSearch) { forfor (int i = 0; i < str.length(); i++){(int i = 0; i < str.length(); i++){ charchar chch = str.charAt(i);= str.charAt(i); forfor (int(int jj = 0; j < toSearch.length; j++){= 0; j < toSearch.length; j++){ ifif (searchChars[j] == ch){(searchChars[j] == ch){ returnreturn i;i; }} }} }} }} }} }}
  • 9. // En un lenguaje dinámico* podemos quitar tipos/clases:// En un lenguaje dinámico* podemos quitar tipos/clases: indexOfAnyindexOfAny((strstr,, toSearchtoSearch){){ when (toSearch) {when (toSearch) { forfor (i = 0; i < str.length(); i++){(i = 0; i < str.length(); i++){ chch = str.charAt(i);= str.charAt(i); forfor ((jj = 0; j < toSearch.length; j++){= 0; j < toSearch.length; j++){ ifif (searchChars[j] == ch){(searchChars[j] == ch){ returnreturn i;i; }} }} }} }} }}
  • 10. // pseudo-codigo// pseudo-codigo indexOfAnyindexOfAny((strstr,, toSearchtoSearch){){ when (toSearch) {when (toSearch) { forfor (i = 0; i < str.length(); i++){(i = 0; i < str.length(); i++){ chch = str.charAt(i);= str.charAt(i); when toSearch(ch) i; // Busca 'ch', retorna iwhen toSearch(ch) i; // Busca 'ch', retorna i }} }} }}
  • 11. // Usando una list-comprehension para iterar// Usando una list-comprehension para iterar indexOfAnyindexOfAny((strstr,, toSearchtoSearch){){ when (toSearch) {when (toSearch) { forfor ([i, ch] in indexed(str)){([i, ch] in indexed(str)){ when toSearch(ch) i;when toSearch(ch) i; }} }} }}
  • 12. // pseudo-codigo// pseudo-codigo indexOfAnyindexOfAny((strstr,, toSearchtoSearch){){ when (toSearch) {when (toSearch) { forfor ([i, ch] in indexed(str)){([i, ch] in indexed(str)){ when toSearch(ch) i;when toSearch(ch) i; }} }} }} ;; Version Clojure;; Version Clojure ((defndefn index-filterindex-filter [coll pred][coll pred] ((whenwhen predpred ((forfor [[idx elt] (indexed coll)[[idx elt] (indexed coll) :when:when (pred elt)] idx)))(pred elt)] idx)))
  • 13. Imperativa Funcional Funciones 1 1 Clases 1 0 Puntos internos de retorno 2 0 Variables 3 0 Ramificaciones 4 0 Operaciones booleanas 1 0 Llamadas a funciones 6 3 Total 18 4 Complejidad de cada versiónComplejidad de cada versión
  • 14. ;; Es correcta esta implementación?;; Es correcta esta implementación? ((defndefn indexedindexed [s] ([s] (mapmap vector (vector (iterateiterate inc 0) s))inc 0) s)) ((defndefn index-filterindex-filter [coll pred][coll pred] ((whenwhen predpred ((forfor [[idx elt] (indexed coll)[[idx elt] (indexed coll) :when:when (pred elt)] idx)))(pred elt)] idx))) ;; StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0;; StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0 ;; StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3;; StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3 (index-filter "zzabyycdxx" #{z a})(index-filter "zzabyycdxx" #{z a}) ;; => (;; => (00 1 2)1 2) (index-filter "zzabyycdxx" #{b y})(index-filter "zzabyycdxx" #{b y}) ;; => (;; => (33 4 5)4 5)
  • 15. ;; index-filter retorna una lista* de TODOS los calces!;; index-filter retorna una lista* de TODOS los calces! ;; Indices de 'cara' en una lista de tiradas de moneda:;; Indices de 'cara' en una lista de tiradas de moneda: (index-filter [(index-filter [:c :s :c :c :s :s :c :s :c :s :c:c :s :c :c :s :s :c :s :c :s :c] #{] #{:c:c})}) ;; => (0 2 3 6 8 10);; => (0 2 3 6 8 10) ;; Cuál es el primer número de Fibonacci mayor que 1000?;; Cuál es el primer número de Fibonacci mayor que 1000? ((defndefn fibofibo [][] ((mapmap first (first (iterateiterate ((fnfn [[a b]] [b (+ a b)]) [0 1])))[[a b]] [b (+ a b)]) [0 1]))) ((firstfirst (index-filter (fibo) #(> % 1000)))(index-filter (fibo) #(> % 1000))) ;; => 17;; => 17 ((nthnth (fibo) 17)(fibo) 17) ;; => 1597;; => 1597
  • 16. ¿Qué versión es más general?¿Qué versión es más general? Imperativa Funcional Busca dentro de Strings Busca en Secuencias Busca sólo caracteres Busca usando cualquier función predicado Retorna el primer calce Retorna una lista lazy de todos los calces
  • 17. Euler #4:Euler #4: Mayor producto palíndromoMayor producto palíndromo •• Número palíndromo: si es el mismo, escrito al revésNúmero palíndromo: si es el mismo, escrito al revés (1.234.321)(1.234.321) •• El mayor palíndromo que es producto de 2 númerosEl mayor palíndromo que es producto de 2 números de 2 cifras esde 2 cifras es 90099009 = 91 x 99= 91 x 99 •• Encontrar el mayor producto de números de 3 cifrasEncontrar el mayor producto de números de 3 cifras que sea palíndromoque sea palíndromo
  • 18. // Palindromos.java// Palindromos.java public classpublic class Palindromos {Palindromos { public staticpublic static booleanboolean isPalinisPalin(Integer(Integer nn) {) { StringString nsns = n.toString();= n.toString(); StringString reversereverse = new StringBuffer(ns).reverse().toString();= new StringBuffer(ns).reverse().toString(); returnreturn nstring.equals(reverse);nstring.equals(reverse); }} public staticpublic static void main(String[]void main(String[] argsargs) {) { IntegerInteger maxmax = 0;= 0; forfor (int(int ii = 100; i <= 999; i++) {= 100; i <= 999; i++) { forfor (int(int jj = 100; j <= 999; j++) {= 100; j <= 999; j++) { IntegerInteger prodprod = i * j;= i * j; ifif (isPalin(prod) && prod > max) {(isPalin(prod) && prod > max) { max = prod;max = prod; }} }} }} System.out.println(max);System.out.println(max); }} }}
  • 19. # euler-004.py# euler-004.py defdef palin(x):palin(x): returnreturn strstr(x) ==(x) == strstr(x)[::-1](x)[::-1] palinspalins = [x*y= [x*y forfor xx inin range(100, 1000) range(100, 1000) forfor yy inin range(x, 1000)range(x, 1000) ifif palin(x*y)]palin(x*y)] print(max(palins))print(max(palins))
  • 20. # euler-004.rb# euler-004.rb puts (100..999).flat_map{|a| (a..999).flat_map {|b| a*b}}puts (100..999).flat_map{|a| (a..999).flat_map {|b| a*b}} .select{|x| x.to_s == x.to_s.reverse}.select{|x| x.to_s == x.to_s.reverse} .max.max # euler-004.groovy# euler-004.groovy defdef maxmax = (100..999).collect{x->(100..999).collect{y->x*y}}= (100..999).collect{x->(100..999).collect{y->x*y}} .flatten().flatten() .findAll{ it.toString() == it.toString().reverse() }.findAll{ it.toString() == it.toString().reverse() } .max().max() println maxprintln max
  • 21. ;; euler-004.clj;; euler-004.clj ((defndefn palin? [x]palin? [x] (= ((= (strstr x) (x) (apply strapply str ((reversereverse ((strstr x)))))x))))) ((printlnprintln ((reducereduce maxmax ((forfor [x ([x (rangerange 100 1000)100 1000) y (y (rangerange x 1000)x 1000) :let:let [prod (* x y)][prod (* x y)] :when:when (palin? prod)] prod))))(palin? prod)] prod))))
  • 22. ConclusiónConclusión
  • 23. •• Mayor nivel de abstracción:Mayor nivel de abstracción: más énfasis en el→más énfasis en el→ quéqué y no en ely no en el cómocómo →→ menos código que comprendermenos código que comprender →→ a veces, código más genérico y re-utilizablea veces, código más genérico y re-utilizable •• EnEn ClojureClojure se prefieren funciones puras*se prefieren funciones puras* son más fáciles de entender→son más fáciles de entender→ →→ más fáciles de testear (no se necesitamás fáciles de testear (no se necesita mockingmocking)) →→ se pueden guardarse pueden guardar en cachéen caché (memoize f)(memoize f) →→ se pueden paralelizarse pueden paralelizar fácilmentefácilmente (pmap f)(pmap f) Beneficios de PFBeneficios de PF
  • 24. FinFin
  • 25. CréditosCréditos Portada - “Lights of Ideas” por Saad Faruque http://www.flickr.com/photos/cblue98/7254347346/sizes/l/ Fondo - “Gravel Background” por Ember Studio http://www.flickr.com/photos/48013511@N07/7685947954/ Ejemplos en Clojure basados en “Functional Thinking” por Neal Ford http://shop.oreilly.com/product/0636920030393.do