<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4243588728844398089</id><updated>2011-09-30T14:43:52.000+01:00</updated><category term='interactivo'/><category term='compatibilidad'/><category term='xml'/><category term='evaluacion perezosa'/><category term='hibernate'/><category term='ejemplo'/><category term='scala'/><category term='emacs'/><category term='javascript'/><category term='java'/><category term='funcional'/><category term='clojure'/><category term='funcion'/><category term='reduce'/><category term='intro'/><category term='tutorial'/><category term='repl'/><category term='iterate'/><category term='recur'/><category term='introduccion'/><category term='cloud'/><category term='jvm'/><category term='gae'/><category term='ie'/><category term='netbeans'/><category term='1.0'/><category term='criteria'/><category term='grails'/><category term='instalacion'/><category term='multilenguaje'/><category term='appengine'/><category term='sintaxis'/><category term='groovy'/><category term='haskell'/><category term='concurrencia'/><category term='composition'/><category term='let'/><category term='filosofia'/><category term='anonima'/><category term='eclipse'/><category term='clojure tdd coderetreat'/><category term='inmutabilidad'/><category term='closures'/><category term='ide'/><category term='computing'/><category term='google'/><title type='text'>Cerraduras: clojure en español</title><subtitle type='html'>Blog sobre programacion enfocado a Clojure y a la programacion funcional en general</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>18</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-8344221651923465313</id><published>2011-09-12T19:08:00.000+01:00</published><updated>2011-09-14T11:12:05.744+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='closures'/><category scheme='http://www.blogger.com/atom/ns#' term='criteria'/><category scheme='http://www.blogger.com/atom/ns#' term='composition'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Abracadabra: componiendo criterios de hibernate en grails.</title><content type='html'>&lt;blockquote&gt;"Como decíamos ayer..."&amp;nbsp; &lt;i&gt;Fray Luis de León, Miguel de Unamuno et alii&lt;/i&gt;&lt;/blockquote&gt;&lt;div style="text-align: justify;"&gt;En la ultima aplicación que estoy escribiendo en el trabajo he tenido la suerte de usar grails como plataforma de desarrollo. Pese a todos los problemas que nos encontramos, casi todos originados en ser una tecnología relatívamente joven y que esta en continuo desarrollo, ha supuesto para nosotros un salto en el tiempo de ocho años. Hasta ahora estábamos usando la JDK 1.4, J2EE 1.4, struts 1 y persistencia manual en java y SQL, con lo que el cambio ha sido cualitativo.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;En mis primerizos intentos de conseguir que el código sea reutilizable y evitar su duplicación no siempre he encontrado facilidades en la librería, o, lo mas seguro, no he sabido usarla de la forma correcta.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Uno de los puntos donde he encontrado dificultad ha sido a la hora de separar en elementos manejables las &lt;a href="http://groovy.codehaus.org/Closures+-+Formal+Definition"&gt;closures&lt;/a&gt; estáticas que contienen llamadas a métodos que forman un minilenguaje (o DSL) en si mismos. Estos métodos normalmente no existen en el contexto sintáctico donde están esas closures sino que pertenecen a algún otro objeto (&lt;a href="http://groovy.codehaus.org/Builders"&gt;normalmente un "builder"&lt;/a&gt;), aunque puede también usar las variables y métodos definidos en su ambito sintactico. En algún momento la librería "introduce" a la closure dentro del contexto del builder (por ejemplo con &lt;a href="http://mrhaki.blogspot.com/2009/09/groovy-goodness-with-method.html"&gt;with&lt;/a&gt;) con lo que los métodos ya tienen sentido, la closure esta totalmente cerrada y puede ser ejecutada. &lt;a href="http://grails.org/doc/latest/ref/Domain%20Classes/createCriteria.html"&gt;Un ejemplo, usado en grails,&lt;/a&gt; es el uso de las &lt;a href="http://docs.jboss.org/hibernate/core/3.5/javadocs/org/hibernate/Criteria.html"&gt;Criteria de hibernate&lt;/a&gt; para definir consultas sobre entidades en la base de datos:&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1212513.js?file=criteriaExample.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;No tiene mala pinta pero una vez que te pones a usarlas te encuentras algunas limitaciones, una de ellas es que no puedes componer facilmente las closures para poder separar los diferentes criterios y hacerlos genéricos para no repetirlos una y otra vez. Si usas directamente el api de Criteria puedes componer los &lt;a href="http://docs.jboss.org/hibernate/core/3.5/javadocs/org/hibernate/criterion/Criterion.html"&gt;criterios&lt;/a&gt; creando instancias de los mismo y &lt;a href="http://docs.jboss.org/hibernate/core/3.5/javadocs/org/hibernate/Criteria.html#add%28org.hibernate.criterion.Criterion%29"&gt;añadirlos&lt;/a&gt; a la instancia misma de la Criteria. Sin embargo en &lt;a href="http://grails.org/doc/latest/api/grails/orm/HibernateCriteriaBuilder.html"&gt;la solución de grails&lt;/a&gt; esto no es posible ya que aunque es mas breve y expresiva no expone los métodos para añadir dinámicamente criterios (o al menos no he encontrado la manera de hacerlo). Mi objetivo final era conseguir algo así:&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1212513.js?file=objetivo.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;O sea poder componer la closure final con closures mas pequeñas y manejables. También quería conseguir poder parametrizarlas tanto con datos externos como con los valores de la instancia en la que están definidas, consiguiendo un filtro que usa los campos de la instancia sobre la que es llamada como datos de ejemplo para realizar la consulta. En mi caso los métodos genéricos que encapsulan los criterios están en la superclase:&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1212513.js?file=base.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Solamente se añade el filtro de cada propiedad si esta informado y el carácter del filtro es lo mas abierto posible,  usando "ilike" en los campos de cadena, "in" en los campos que definen relaciones uno a muchos con otras entidades, etc. También quiero subrayar que las entidades "maestras" se recuperan de forma recursiva, reutilizando el filtro definido en su clase correspondiente.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La pieza que falta para completar el puzzle es el operador &lt;b&gt;"&amp;gt;&amp;gt;&amp;gt;"&lt;/b&gt; que se esta utilizando en el código para combinar las closures. Este operador no existe como tal en la versión actual de groovy. De hecho hace relativamente poco que en groovy (en la versión 1.8) se han añadido operaciones y métodos funcionales que actúan sobre las closures, tales como &lt;a href="http://mrhaki.blogspot.com/2009/09/groovy-goodness-add-some-curry-for.html"&gt;su aplicacion parcial&lt;/a&gt; y su &lt;a href="http://mrhaki.blogspot.com/2011/04/groovy-goodness-chain-closures-together.html"&gt;composición&lt;/a&gt;. Supongo que la reciente recuperación del paradigma funcional (con lenguajes como Clojure, Scala o Haskell) ha favorecido que finalmente estén disponibles. En mi caso todavía estoy usando la versión 1.7 y tenia que añadir la operación de composición. Sin embargo al copiarla de la versión actual la cosa no marchaba. Lo vemos en este ejemplo que simula el comportamiento del builder de grails y la composición oficial de la versión 1.8:&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1212513.js?file=compositionDelegation.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;a href="http://groovyconsole.appspot.com/script/553001#"&gt;Como se puede comprobar en la consola de groovy&lt;/a&gt; se produce un error ya que al componer ambas closures no se propaga el contexto de ejecución de la closure resultante a las closures que la componen, por lo que groovy busca los métodos "eq" e "in" en el contexto mas amplio que es el script mismo donde estamos escribiendo el código. Al no encontrarlo en ningún nivel nos devuelve el consabido error.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La closure se liga al contexto de un objeto usando la propiedad delegate de la misma. Para poder conseguir la ligazón tuve que implementar un método de composición que propagara esa propiedad de la closure resultante a las que están siendo compuestas:&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1212513.js?file=DarkMagic.groovy"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Como se puede observar en el código "simplemente" se crea una nueva closure que llama a las dos que están siendo compuestas, a las que previamente les ha asignado su propio delegate para introducirlas en el contexto de computación. La implementación no esta muy cuidada y tal vez tenga errores, vamos, que no hay garantías. &lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La verdad es que no acabo de sentirme cómodo con la solución a la que he llegado, aunque en el camino he aprendido algo del funcionamiento interno de las closures, me parece que es demasiado enrevesada para lo que quería conseguir. En principio soy contrario al &lt;a href="http://en.wikipedia.org/wiki/Monkey_patch"&gt;monkey patching&lt;/a&gt; más aun si se hace sobre clases básicas y al uso de la sobrecarga de operaciones. Seguramente se puede hacer de una manera más sencilla, aunque no la he encontrado. Como siempre vuestros comentarios tal vez puedan arrojar un poco mas de luz sobre el asunto.&lt;/div&gt;&lt;br /&gt;Hasta mañana.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-8344221651923465313?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/8344221651923465313/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2011/09/abracadabra-componiendo-criterios-de.html#comment-form' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/8344221651923465313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/8344221651923465313'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2011/09/abracadabra-componiendo-criterios-de.html' title='Abracadabra: componiendo criterios de hibernate en grails.'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-8963127072128801802</id><published>2010-12-09T08:00:00.005Z</published><updated>2011-08-13T15:19:38.221+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ide'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='netbeans'/><category scheme='http://www.blogger.com/atom/ns#' term='instalacion'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><category scheme='http://www.blogger.com/atom/ns#' term='introduccion'/><title type='text'>Primeros pasos con Clojure</title><content type='html'>&lt;div style="text-align: justify;"&gt;La documentación de Clojure igual no es la mejor del mundo. En un lenguaje joven y mucha información esta repartida entre los blogs de los cada vez mas numerosos entusiastas del lenguaje. Sin embargo se ha dado un paso mas para que los principiantes tengan un referente principal a la hora de instalar y configurar Clojure de una forma sencilla. Todo ello gracias a la labor de Stuart Halloway, autor de un interesante blog y del primer libro sobre Clojure: &lt;a href="http://pragprog.com/titles/shcloj/programming-clojure"&gt;&lt;span style="font-style: italic;"&gt;Programming Clojure&lt;/span&gt;&lt;/a&gt;.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La pagina principal de la wiki es &lt;a href="http://dev.clojure.org/display/doc/Getting+Started"&gt;esta&lt;/a&gt;. En ella hay una lista de enlaces a concisos tutoriales sobre las posibles formas de instalar y usar Clojure, según el &lt;a href="http://es.wikipedia.org/wiki/Entorno_de_desarrollo_integrado"&gt;IDE&lt;/a&gt; o editor que mas rabia nos de:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.enclojure.org/"&gt;Primeros pasos con Netbeans y Enclojure.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://dev.clojure.org/display/doc/Getting+Started+with+Eclipse+and+Counterclockwise"&gt;Primeros pasos con Eclipse y Counterclockwise.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://dev.clojure.org/display/doc/Getting+Started+with+La+Clojure+and+IntelliJ+IDEA"&gt;Primeros pasos con IntelliJ IDEA y La Clojure.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://dev.clojure.org/display/doc/Getting+Started+with+Emacs"&gt;Primeros pasos con Emacs&lt;/a&gt; (¡Este es el mio!).&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/technomancy/leiningen"&gt;Primeros pasos con Leiningen.&lt;/a&gt; &lt;ul&gt;&lt;li&gt;Leiningen es una herramienta de gestión de dependencias y compilación, instalación, etc, construido sobre &lt;a href="http://es.wikipedia.org/wiki/Ant"&gt;Ant&lt;/a&gt; y &lt;a href="http://es.wikipedia.org/wiki/Maven"&gt;Maven&lt;/a&gt; pero usando Clojure para su definición. Es, de facto la herramienta estandar de manejo de proyectos dentro de la comunidad de clojure y su manejo es tan sencillo que merece la pena elegirlo para tus proyectos por pequeños que sean.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://dev.clojure.org/display/doc/Getting+Started+with+Cake"&gt;Primeros pasos con Cake.&lt;/a&gt; &lt;ul&gt;&lt;li&gt;Otra herramienta de construccion y despliegue de proyectos, facilmente instalable si tienes ruby ya instalado en tu equipo. Tiene la ventaja de que mantiene una maquina virtual de java permanente para evitar la lentitud de los arranques continuos de la misma.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/liebke/cljr/wiki"&gt;Primeros pasos con cljr&lt;/a&gt; &lt;ul&gt;&lt;li&gt;Una de las mejores opciones para empezar a usar el lenguaje. Consiste basicamente en un gestor de dependencias automatico y una serie de herramientas y utilidades para facilitar el uso de clojure fuera de un proyecto concreto.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://dev.clojure.org/display/doc/Getting+Started+with+Vim"&gt;Primeros pasos con Vim.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://dev.clojure.org/display/doc/Getting+Started+with+Maven"&gt;Primeros pasos con Maven.&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Como veis hay donde elegir. También tanto Stuart Halloway como el creador de Clojure, Rich Hickey han publicado un proyecto base pensado para aprender e iniciarse en Clojure con lo todo lo necesario: &lt;a href="http://github.com/relevance/labrepl"&gt;labrepl&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;ACTUALIZACION&lt;/h4&gt;Afortunadamente los recursos para iniciarse con clojure crecen dia a dia. Entre los mas interesantes que han aparecido despues de este post estan los siguientes:&lt;br /&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;Una repl interactiva online done probar clojure sin instalar nada: &lt;a href="http://try-clojure.org/"&gt;try-clojure&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Un pagina excelente para practicar clojure, con problemas de diferentes dificultad y la posibilidad de competir por escribir el codigo mas breve: &lt;a href="http://www.4clojure.com/"&gt;4clojure&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Una forma que se ha puesto de moda ultimamente es aprender los principios de un lenguaje con los koans, &lt;a href="http://sett.ociweb.com/sett/settJan2011.html"&gt;en esta pagina&lt;/a&gt; te guian como empezar con ellos con ruby, javascript y como no clojure.&lt;/li&gt;&lt;li&gt;Una pagina en las que se intenta centralizar todos los recursos utiles para aprender cojure, desde como instalarlo a listas de tutoriales, libros, etc. Imprescindible si quieres aprender el lenguaje: &lt;a href="http://learn-clojure.com/"&gt;learn-clojure.com&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Recursos en la web con documentacion y &lt;span style="font-weight: bold;"&gt;ejemplos&lt;/span&gt; acerca de Clojure: &lt;a href="http://clojuredocs.org/"&gt;clojuredocs.org&lt;/a&gt; y &lt;a href="http://clojure-examples.appspot.com/"&gt;&lt;span class="f"&gt;&lt;cite&gt;&lt;b&gt;clojure&lt;/b&gt;-&lt;b&gt;examples&lt;/b&gt;.appspot.com&lt;/cite&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="f"&gt;Una &lt;a href="http://faustus.webatu.com/clj-quick-ref.html"&gt;guia rapida&lt;/a&gt; de las funciones del nucleo de clojure.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="f"&gt;Tutoriales acerca de como instalar y dar los primeros pasos en clojure: &lt;a href="http://clojure-notes.rubylearning.org/"&gt;clojure-notes.rubylearning.org&lt;/a&gt; y si eres valiente, tienes un mac o linux y ganas de pegarte con las cosas &lt;a href="http://programmingzen.com/2010/07/13/how-to-setup-clojure-from-scratch/"&gt;how-to-setup-clojure-from-scratch&lt;/a&gt;, si tienes un ubuntu tambien hay &lt;a href="http://clojure.roboloco.net/?p=953"&gt;un post especifico&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-8963127072128801802?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/8963127072128801802/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/04/primeros-pasos-con-clojure.html#comment-form' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/8963127072128801802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/8963127072128801802'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/04/primeros-pasos-con-clojure.html' title='Primeros pasos con Clojure'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-2668400677679092526</id><published>2010-11-21T19:52:00.014Z</published><updated>2011-01-10T23:52:24.611Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='clojure tdd coderetreat'/><title type='text'>Pruebo, luego programo.</title><content type='html'>&lt;div style="text-align: justify;"&gt;He tenido la suerte de poder participar en el &lt;a href="http://coderetreat.ning.com/profiles/blogs/how-to-run-a-coderetreat"&gt;code retreat&lt;/a&gt; &lt;a href="http://agilismo.es/index.php?option=com_content&amp;amp;view=article&amp;amp;id=103:coderetreat-en-donostia&amp;amp;catid=35:evento"&gt;que se celebro el Sábado en Donosti&lt;/a&gt;. ¿Que es un code retreat? Pues es una reunión de programadores que ejercitan sus conocimientos y aprenden y mejoran con ese ejercicio y con su puesta en común entre todos. Una buena forma de aprendizaje a través de la practica y la colaboración. Pero no solo esto, otro de los objetivos es replantearse los propios conocimientos y practicas y para ello la dinámica estaba orientada:&lt;br /&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Los ejercicios se llevan a cabo &lt;a href="http://es.wikipedia.org/wiki/Programaci%C3%B3n_en_pareja"&gt;en parejas&lt;/a&gt;, para potenciar la programación colaborativa.&lt;/li&gt;&lt;li&gt;El problema a resolver o representar en código es el mismo para todos y cada intento de hacerlo duraba estrictamente 45 minutos (osease un &lt;a href="http://es.wikipedia.org/wiki/T%C3%A9cnica_Pomodoro"&gt;pomodoro&lt;/a&gt;). En nuestro caso el problema a resolver fue &lt;a href="http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life"&gt;el juego de la vida de Conway&lt;/a&gt;. Aunque el objetivo real no era resolver el problema por supuesto.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Después de cada sesión había &lt;span style="font-weight: bold;"&gt;que borrar todo el código escrito&lt;/span&gt; antes de compartir entre todos la experiencia.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Como principio general se estableció &lt;a href="http://es.wikipedia.org/wiki/Tdd"&gt;el desarrollo guiado por las pruebas&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Aparte se pusieron restricciones sorpresa para evitar entrar de ninguna manera en una rutina.&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;Todo ello para conseguir una nueva visión de la programación y para romper los esquemas, el bagaje que muchas veces te hace ser mas rígido y te impide aprender y avanzar. Y para conseguirlo de forma radical es necesario medidas radicales.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Por supuesto contar con un &lt;a href="http://twitter.com/ecomba"&gt;maestro de ceremonias adecuado&lt;/a&gt; es casi imprescindible y Enrique lo hizo a la perfección compartiendo sus valiosos conocimientos de forma totalmente desinteresada. El acto no pudo haber existido sin el tiempo y &lt;a href="http://agilismo.es/index.php?option=com_content&amp;amp;view=article&amp;amp;id=103:coderetreat-en-donostia&amp;amp;catid=35:evento"&gt;el esfuerzo de los organizadores y de los patrocinadores&lt;/a&gt;. Desde aquí mi reconocimiento a su generosidad. Finalmente pero no menos importante también hay que reconocer el papel de todos los asistentes al acto ya que entre todos ayudamos un poco a que fuera un éxito.&lt;br /&gt;&lt;/div&gt;Nunca había practicado ninguna de las técnicas que he descrito y solo tenia cierto conocimiento teórico de lo que había podido leer en blogs y artículos. Un conocimiento totalmente inútil y que intente olvidar para limpiar la mente de prejuicios.&lt;br /&gt;&lt;div style="text-align: justify;"&gt;El objetivo claro fue hacernos mejores programadores o sea que nuestro código fuera mas elegante, mas simple, mas fiable y mantenible. La prueba desde ese punto de vista pierde su valor como elemento externo al programa, muchas veces escrito a posteriori y se convierte en el medio para alejarnos del código real y mirarlo desde fuera incluso cuando aun esta en nuestra mente luchando por salir y apoderarse de nuestros dedos. La prueba nos aleja de el para mirarlo con ojos nuevos y sospechosos.&lt;br /&gt;&lt;/div&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;Sí, nuestro &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;código&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; siempre es sospechoso.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;A la vez la prueba nos hace seguir pegados al objetivo y al propósito del código todavía no escrito y no nos separa totalmente de lo que es la programación ya que es en si misma código. Esa es su ventaja y su inconveniente ya que hay otras maneras de alejarnos del código: haciendo dibujos o simplemente no haciendo otra cosa que pensar en el. La desventaja de la prueba es que sigue siendo código en el que podemos regodearnos, dándole mas importancia de la debida y que puede acabar siendo tan imperfecto o mas que el código real que todavía no hemos escrito (y que puede acabar siendo empobrecido por la prueba y no al revés).&lt;br /&gt;&lt;/div&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;Sí, se corre el riesgo de escribir dos veces un &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;código&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; mal hecho. Nadie dijo que la &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;tdd&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; fuera &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;mágica&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;h3&gt;Aprendizajes y collejas varias&lt;/h3&gt;&lt;div style="text-align: justify;"&gt;Para evitarlo Enrique nos daba collejas virtuales, tanto en mitad de los ejercicios como en las retrospectivas posteriores para sacarnos de nuestros raíles, viejos o los que íbamos creando en el momento. Borrar el código antes de hablar de el, tener que consensuar los nombres y el siguiente paso a seguir, cortar el ejercicio justo cuando la cosa empezaba a calentarse. Todo orientado a alejarnos del código y volverlo a mirar con otros ojos.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;La prueba bien hecha no se deja arrastrar por el código todavía no escrito que pulula en nuestra cabeza, lo domina y lo encierra y le obliga a seguirla:&lt;br /&gt;&lt;/div&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt; Le debe obligar a &lt;a href="http://en.wikipedia.org/wiki/KISS_principle"&gt;ser mas simple&lt;/a&gt;: para ello Enrique nos obligo a escribir todo el código necesario dentro de la prueba y solo darle entidad propia en cuanto detectaramos &lt;a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;repeticiones reales&lt;/a&gt; en las pruebas. En otro momento nos obligo a que las funciones o métodos no fueran de mas de cuatro lineas.&lt;br /&gt;&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Debe usar los nombres mas "adecuados" (totalmente autodescriptivos,no ambiguos, lo mas cortos posible)  a la lógica de negocio y al problema que va a resolver. En cada retrospectiva Enrique incidía y cuestionaba los bautizos que hacíamos.&lt;br /&gt;&lt;/li&gt;&lt;li style="text-align: justify;"&gt;&lt;a href="http://en.wikipedia.org/wiki/Solid_%28object-oriented_design%29"&gt;Le debe dar justo la responsabilidad que necesita para hacer bien su trabajo&lt;/a&gt; sin dependencias innecesarias y lo mas alejadas de la implementaciones concretas. El mismo hecho de hacer la prueba te conduce a ello ya que probar un fragmento de código es mas difícil y costoso cuanto mas dependencias externas tienes que manejar en la prueba (uso de mocks e inicializaciones costosas). Enrique nos prevenía de la implementación concreta que luchaba por salir de nuestros dedos y que amenazaba con encerrar y anclar nuestro diseño antes de tiempo.&lt;/li&gt;&lt;li style="text-align: justify;"&gt;La prueba debe contagiar al código de su carácter declarativo, para lo que obviamente debe ser ella misma lo mas declarativa posible. Enrique nos prohibió usar números en las pruebas para intentar hacernos ver que la mejor forma de que la prueba nos dijera lo que quería es darle un nombre que lo expresara de forma totalmente descriptiva. No lo consiguió y tuvo que borrar nuestro código (otra colleja) y señalarnos con el dedo (y aun asi nos costo asumirlo). Cuando vimos: &lt;span style="font-style: italic;"&gt;public class TestCelulaCuandoEstaViva { public void muereCuandoTieneMenosDeDosVecinos () {assert(true)}}&lt;/span&gt; el código lleno de ifs, operadores de comparación y números que habíamos guardado celosamente en nuestras cabezas y que guiaba secretamente nuestras pruebas murió un poco mas. &lt;a href="http://pragprog.com/articles/tell-dont-ask"&gt;Tell, dont ask&lt;/a&gt;, my friend.&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Debemos poder hacer las pruebas tanto desde arriba hacia abajo como al revés y elegir el camino adecuado en cada momento (o combinarlos, primero hacia abajo y luego de vuelta como nos mostró Enrique). &lt;a href="http://blog.objectmentor.com/articles/2010/06/03/tdd-in-clojure"&gt;La elección debe ser cuidadosa&lt;/a&gt; y debe tener en cuenta el dominio, las herramientas, el lenguaje con el contamos, etc.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt; Un tesoro nos llevamos de Donosti, seguro que hubo mas enseñanzas que se me han olvidado o que ni siquiera capte pero estoy contento. Pero, espera un momento, yo ya conocía todos esos preciosos principios y buenas practicas en teoría e incluso intento con mayor o menor éxito aplicarlos en mi código. Geniales programadores los llevan a la practica todos los días sin hacer un test. Se alejaran del código y como paso previo pensaran en el teniendo en cuenta todas estos principios y algunos mas. Incluso estoy seguro que el primer código que piense gente como Enrique ya sera cristalino (al menos comparado con el mio).&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Como otra opción para los programadores de a pie queda el hacer prototipos del código y repensarlo y reescribirlo las veces que haga falta. Equivocarse una y otra vez y aprender de los errores.&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Entonces, ¿para que las pruebas?&lt;/h3&gt;&lt;div style="text-align: justify;"&gt;Buena pregunta ya que, en mi opinión, no hay que aceptar las metodologías sin mas ya que también son sospechosas (igual que lo es el código). Igual me perdí algo en el code retreat que eliminara todo mi escepticismo. Dejare a mis comentaristas la oportunidad de contestar aunque puedo adelantar que en primer lugar aparece el valor original de la prueba que hasta ahora habíamos obviado: monitorizar el código de forma automática y aumentar nuestra confianza en el, describir y documentar los casos de uso y la lógica de negocio. El hacer la prueba primero tiene la consecuencia obvia de que seguro que la haces. Por otro lado te obliga de forma metódica a pensar en el código antes de escribirlo (cosa que no suele hacerse siempre a no ser que tengas una gran disciplina) Seguro que se os ocurren mas ventajas.&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Clojure y el TDD&lt;/h3&gt;&lt;div style="text-align: justify;"&gt;Por supuesto fui con mis paréntesis a la sesión con un poco de miedo que provocaran urticaria y dispuesto a amoldarme a cualquier lenguaje sobre todo desconocido para mi como oportunidad para aprender. Debí haber previsto que todos venían dispuestos a aprender sin prejuicios y no les importo o incluso estuvieron encantados (¡cuando &lt;a href="http://twitter.com/jmbeas"&gt;@jmbeas&lt;/a&gt; empezó a recordar sus tiempos de emacs y common lisp tuve que seguirle yo a el!) de usar clojure para los ejercicios, &lt;a href="http://twitter.com/kinisoftware"&gt;@kinisoftware&lt;/a&gt; también acepto sin problema hacerlo en clojure a la vez que me guiaba por mis primeros balbuceos en los tests. Eso tal vez sesgo un poco el objetivo principal pero creo que pude mostrar unas pinceladas del lenguaje sin olvidarnos del todo de el.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Hay gente que cuestiona la pertinencia de la TDD en un lenguaje funcional como Clojure, pero dentro de la comunidad también hay opiniones contrarias y al menos el testing tiene su lugar ya en &lt;a href="http://richhickey.github.com/clojure/clojure.test-api.html"&gt;el mismo núcleo del lenguaje&lt;/a&gt;. Aparte hay &lt;a href="https://github.com/stuartsierra/lazytest"&gt;varias&lt;/a&gt; &lt;a href="https://github.com/marick/Midje"&gt;librerías&lt;/a&gt; magnificas para ponerlo en practica. Personalmente creo que aunque no tiene el mismo significado o importancia en un lenguaje orientado a objetos y dinámico (en el que casi es una locura programar sin hacer tdd) que en uno funcional y que &lt;a href="http://clojure.org/functional_programming"&gt;promociona la inmutabilidad&lt;/a&gt; y evita &lt;a href="http://clojure.org/state"&gt;el estado&lt;/a&gt;, si que cumple su papel. No hay mejor referencia que &lt;a href="http://blog.objectmentor.com/articles/category/uncle-bobs-blatherings"&gt;los posts&lt;/a&gt; que ha escrito &lt;a href="http://twitter.com/unclebob"&gt;@unclebob&lt;/a&gt; sobre clojure y tdd o &lt;a href="http://www.exampler.com/blog/category/clojure/"&gt;los de&lt;/a&gt; &lt;a href="http://twitter.com/marick"&gt;@marick.&lt;/a&gt;&lt;br /&gt;Fue curioso como la orientación de objetos fue, en mi opinión, mas un estorbo que una ayuda para las sesiones. Los objetos (todos con mayúsculas Célula, Tablero, Juego,Dios) que modelaban el problema, sus relaciones y sus responsabilidades rondaban la cabeza de los asistentes y creo que tiraban de los tests anclandolos y no dejandolos fluir. En mi caso era las estructura de datos simples  la que me rondaban y las funciones para transformarlas (vectores, mapas) pero creo que esa diferencia iba a mi favor pues con elementos tan simples y genéricos (que hay mas abstracto,generico, componible y simple que una funcion o un mapa)  no necesitas crear abstracciones a posteriori ni mocks para aislar los tests del diseño e implementación concreto. ¡¡¡Corregirme si me equivoco!!!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-2668400677679092526?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/2668400677679092526/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/11/pruebo-luego-programo.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/2668400677679092526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/2668400677679092526'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/11/pruebo-luego-programo.html' title='Pruebo, luego programo.'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-6163367999960057420</id><published>2010-09-28T21:04:00.015+01:00</published><updated>2010-12-20T10:11:05.901Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='filosofia'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Scala vs y Clojure (Round 1)</title><content type='html'>&lt;h3&gt;&lt;a href="http://www.scala-lang.org/"&gt;Un lenguaje escalable&lt;/a&gt;: tanta complejidad como necesites.&lt;/h3&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Una ventaja de que por la &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_0"&gt;península&lt;/span&gt; vayamos retrasados en esto de lo &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;tecnológico&lt;/span&gt; es que sea mas &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_2"&gt;difícil&lt;/span&gt; que un post como este pueda iniciar un guerra. Pero por si acaso quiero aclarar que aunque mi lenguaje preferido en la intimidad sea &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Clojure&lt;/span&gt;&lt;/span&gt;, &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;también&lt;/span&gt; aprecio &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Scala&lt;/span&gt;&lt;/span&gt;, al menos en lo que ha acercado a la &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;JVM&lt;/span&gt;&lt;/span&gt; elementos de lenguajes como &lt;a href="http://haskell.org/haskellwiki/Haskell"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Haskell&lt;/span&gt;&lt;/span&gt;&lt;/a&gt; y la familia de los &lt;a href="http://en.wikipedia.org/wiki/ML_%28programming_language%29"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;ML&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;Ambos lenguajes comparten ciertos aspectos pero difieren lo suficiente como para no ser excluyentes dentro de los nuevos lenguajes funcionales que corren sobre la &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;JVM&lt;/span&gt;&lt;/span&gt;. El mismo creador de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;Scala&lt;/span&gt;&lt;/span&gt;, &lt;a href="http://twitter.com/#%21/odersky"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;Martin&lt;/span&gt;&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;Odersky&lt;/span&gt;&lt;/span&gt;&lt;/a&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;defendía&lt;/span&gt; esta postura &lt;a href="http://blog.fogus.me/2010/08/06/martinodersky-take5-tolist/"&gt;en esta entrevista&lt;/a&gt;: para que "gane" uno de ellos no tiene porque perder el otro.&lt;br /&gt;Y la diferencia fundamental esta en las razones que ambos surgieran y en su misma &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_14"&gt;filosofía&lt;/span&gt;, antes incluso de las diferencias &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_15"&gt;técnica&lt;/span&gt;. Esa diferencia se traduce &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_16"&gt;también&lt;/span&gt; en sus respectivas comunidades,&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;&lt;/span&gt; en lo que te exige como programador y aprendiz y en lo te puede dar.&lt;br /&gt;En general estoy convencido que un lenguaje no es absolutamente mejor a cualquier otro sino mejor o mas adecuado a un contexto determinado, incluido java o &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;cobol&lt;/span&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;Scala&lt;/span&gt;&lt;/span&gt; desde sus &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_20"&gt;orígenes&lt;/span&gt; ha querido ser "un mejor java", algo &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_21"&gt;así&lt;/span&gt; como un java++. Y aunque &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;ultimamente&lt;/span&gt;&lt;/span&gt; no es la imagen mas popular, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;efectivamente&lt;/span&gt;&lt;/span&gt; lo es. Eso supone que desde su &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_24"&gt;creación&lt;/span&gt; se ha caracterizado por tener una sintaxis similar a la de java y unas &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;construcciones&lt;/span&gt;&lt;/span&gt; parecidas pero mejoradas en cuanto a ser orientado a objetos de una forma mas consistente y expresiva que java. Incluso ha integrado en el lenguaje varios de los patrones de diseño que ya se han establecido casi como norma en java, de una forma sencilla y expresiva.&lt;br /&gt;&lt;br /&gt;Como ejemplo podemos echarle un vistazo a este &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_26"&gt;código&lt;/span&gt; que declara una &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_27"&gt;típica&lt;/span&gt; clase de una &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;aplicación&lt;/span&gt; empresarial:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/747554.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;No &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_29"&gt;tiene&lt;/span&gt; nada de mala pinta para un programador en java que se acerca al lenguaje.&lt;br /&gt;&lt;br /&gt;Por otro lado desde el origen &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;Scala&lt;/span&gt;&lt;/span&gt; ha tomado como ejemplos lenguajes populares en el &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_31"&gt;ámbito&lt;/span&gt; universitario de la "ciencia computacional": &lt;a href="http://caml.inria.fr/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_32"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;Ocaml&lt;/span&gt;&lt;/span&gt;&lt;/a&gt; y &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_33"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;Haskell&lt;/span&gt;&lt;/span&gt;. Tal vez tenga algo que ver que tanto &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_34"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;Odersky&lt;/span&gt;&lt;/span&gt; como &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_35"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;Scala&lt;/span&gt;&lt;/span&gt; &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_36"&gt;están&lt;/span&gt; fuertemente asociados a la Escuela &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_37"&gt;Politécnica&lt;/span&gt; de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_38"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;Lausanne&lt;/span&gt;&lt;/span&gt;. Estos lenguajes (incluido el mismo &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_39"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;Scala&lt;/span&gt;&lt;/span&gt;) &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_40"&gt;están&lt;/span&gt; en la vanguardia de la &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_41"&gt;investigación&lt;/span&gt; en los lenguajes de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_42"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;programación&lt;/span&gt;&lt;/span&gt; lo que ahora mismo es equivalente a decir que profundizan en el paradigma funcional unido a sistemas de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_43"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;tipado&lt;/span&gt;&lt;/span&gt; basados en su &lt;a href="http://en.wikipedia.org/wiki/Type_inference#Hindley.E2.80.93Milner_type_inference_algorithm"&gt;inferencia&lt;/a&gt;. Abstracciones como las &lt;a href="http://www.haskell.org/haskellwiki/Monads"&gt;Monadas&lt;/a&gt; o los &lt;a href="http://www.haskell.org/haskellwiki/Category_theory/Functor"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_44"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;Funtores&lt;/span&gt;&lt;/span&gt;&lt;/a&gt; son poderosas y atractivas intelectualmente, incluso tienen su &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_45"&gt;aplicación&lt;/span&gt; real aunque tal vez no sea evidente a primera vista. Sin embargo su uso en &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_46"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;Scala&lt;/span&gt;&lt;/span&gt; requiere cierta &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_47"&gt;formación&lt;/span&gt; &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_48"&gt;teórica&lt;/span&gt; y un conocimiento mas profundo de su sintaxis. Un &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_49"&gt;código&lt;/span&gt; es &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_50"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;Scala&lt;/span&gt;&lt;/span&gt; que hace un uso intensivo de estos elementos puede parecer tal que &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_51"&gt;así&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/747738.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Viendo este &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_52"&gt;código&lt;/span&gt; el mismo programador que antes &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_53"&gt;asentía&lt;/span&gt; &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_54"&gt;pondrá&lt;/span&gt; los ojos en blanco.&lt;br /&gt;&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_55"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;Scala&lt;/span&gt;&lt;/span&gt; es un &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_56"&gt;híbrido&lt;/span&gt; y su &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_57"&gt;filosofía&lt;/span&gt; es darle todas las opciones posibles al programador aunque suponga hacer el lenguaje mas grande y complejo. Puedes programar orientado a objetos de forma imperativa o funcional, usando datos inmutables o no, usar la &lt;a href="http://en.wikipedia.org/wiki/Lazy_evaluation"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_58"&gt;evaluación&lt;/span&gt; perezosa&lt;/a&gt; o no. Es por esto que lo han comparado a c++ ya que parece que &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_59"&gt;también&lt;/span&gt; este lenguaje &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_60"&gt;nació&lt;/span&gt; un poco con esa &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_61"&gt;filosofía&lt;/span&gt;. &lt;a href="http://lamp.epfl.ch/%7Eodersky/blogs/isscalacomplex.html"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_62"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;Odersky&lt;/span&gt;&lt;/span&gt; tuvo que defender a su lenguaje de esa fama de complejo&lt;/a&gt; pero sin negar que lo fuera, sino defendiendo esa complejidad interna y la "&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_63"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;escabilidad&lt;/span&gt;&lt;/span&gt;" del lenguaje, ya que cada uno puede usar &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_64"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;Scala&lt;/span&gt;&lt;/span&gt; a su manera en cada momento y solo usar la parte mas compleja cuando se necesite &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_65"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;construcciones&lt;/span&gt;&lt;/span&gt; mas poderosas. &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_66"&gt;También&lt;/span&gt; es verdad que el mismo hecho de aglutinar paradigmas y opciones tan diferentes y el ser "escalable" y flexible añade su propia dosis de complejidad en el computo global sea el uso que sea el que le quieras dar.&lt;br /&gt;&lt;br /&gt;El problema de muchos &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_67"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_31"&gt;programadores&lt;/span&gt;&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_68"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_32"&gt;provenientes&lt;/span&gt;&lt;/span&gt; de java con &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_69"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_33"&gt;Scala&lt;/span&gt;&lt;/span&gt; me parece que es que llegan enganchados al cebo de su sintaxis y &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_70"&gt;semántica&lt;/span&gt; &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_71"&gt;básica&lt;/span&gt; parecida y su ligera curva de aprendizaje inicial pero cuando quieren dar un paso mas &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_72"&gt;allá&lt;/span&gt; y usar las partes mas avanzadas el nivel de exigencia y de dificultad aumenta de forma exponencial, al menos en una segunda fase. &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_73"&gt;Después&lt;/span&gt; de todo si te has cambiado de lenguaje es porque se &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_74"&gt;quería&lt;/span&gt; usar algo diferente. Hay que ser pacientes y usar poco a poco esas &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_75"&gt;características&lt;/span&gt; si no se tiene experiencia anterior o un solida base &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_76"&gt;teórica&lt;/span&gt; en lenguajes funcionales &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_77"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_34"&gt;tipados&lt;/span&gt;&lt;/span&gt;. Esa &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_78"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_35"&gt;frustación&lt;/span&gt;&lt;/span&gt; &lt;a href="http://stackoverflow.com/questions/4477484/what-is-preventing-scala-from-gaining-mass-popularity-closed"&gt;aparece como una de las causas que &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_79"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_36"&gt;Scala&lt;/span&gt;&lt;/span&gt; no se haya hecho mas popular&lt;/a&gt;, y se haya agravada por el hecho de que los miembros mas influyentes de su comunidad escriban sobre el lenguaje desde el punto de vista de su parte funcional y sobre el uso mas sofisticado de su sistema de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_80"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_37"&gt;tipado&lt;/span&gt;&lt;/span&gt; y que establecen casi de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_81"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_38"&gt;facto&lt;/span&gt;&lt;/span&gt; que ese uso del lenguaje es el &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_82"&gt;estándar&lt;/span&gt;.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_83"&gt;Según&lt;/span&gt; mi forma de ver &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_84"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_39"&gt;Scala&lt;/span&gt;&lt;/span&gt; puede ser un lenguaje apropiado para entornos de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_85"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_40"&gt;programadores&lt;/span&gt;&lt;/span&gt; java con ganas de aprender pero que quieren empezar con una sintaxis y unas &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_86"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_41"&gt;construcciones&lt;/span&gt;&lt;/span&gt; cercanas y añadir progresivamente elementos mas poderosos cogidos del paradigma funcional. &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_87"&gt;También&lt;/span&gt; es una buena &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_88"&gt;opción&lt;/span&gt; si se quiere un lenguaje que te permite usar un sistema de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_89"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_42"&gt;tipado&lt;/span&gt;&lt;/span&gt; &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_90"&gt;estático&lt;/span&gt; sofisticado y que gracias a su inferencia te ahorra el tener que escribir muchas de las anotaciones de tipos. La gente que no se encuentren &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_91"&gt;cómodos&lt;/span&gt; con los lenguajes &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_92"&gt;dinámicos&lt;/span&gt; y echen de menos la velocidad de &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_93"&gt;ejecución&lt;/span&gt; que te proporcionan los tipos (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_94"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_43"&gt;Scala&lt;/span&gt;&lt;/span&gt; es al menos tan &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_95"&gt;rápido&lt;/span&gt; como java puro) o la posibilidad de validar/documentar tu programa de forma &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_96"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_44"&gt;logica&lt;/span&gt;&lt;/span&gt; con los tipos, valoraran mas el sistema de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_97"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_45"&gt;tipado&lt;/span&gt;&lt;/span&gt; de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_98"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_46"&gt;Scala&lt;/span&gt;&lt;/span&gt;. Mas &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_99"&gt;todavía&lt;/span&gt; si tenemos en cuenta que este sistema es mas flexible, rico y breve en &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_100"&gt;código&lt;/span&gt; que el de java.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_101"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_47"&gt;Clojure&lt;/span&gt;&lt;/span&gt; parte desde un punto de vista totalmente diferente que veremos en la entrada siguiente del blog, pero podemos adelantar que aunque la sintaxis sea totalmente ajena a los lenguajes derivados de &lt;a href="http://es.wikipedia.org/wiki/ALGOL"&gt;Algol&lt;/a&gt; (c,c++,java,&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_102"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_48"&gt;Scala&lt;/span&gt;&lt;/span&gt;,etc,etc) y suponga para muchos un &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_103"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_49"&gt;handicap&lt;/span&gt;&lt;/span&gt; inicial casi insalvable en realidad es mucho mas sencillo que &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_104"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_50"&gt;Scala&lt;/span&gt;&lt;/span&gt;, tanto en la sintaxis como en la &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_105"&gt;semántica&lt;/span&gt; al centrarse y casi obligar a adoptar desde un principio a las &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_106"&gt;característica&lt;/span&gt; funcionales casi puras: &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_107"&gt;inmutabilidad&lt;/span&gt; de los datos, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_108"&gt;separación&lt;/span&gt; entre estos y los algoritmos que los tratan, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_109"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_51"&gt;evaluación&lt;/span&gt;&lt;/span&gt; perezosa, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_110"&gt;&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_52"&gt;separación&lt;/span&gt;&lt;/span&gt; entre el valor (inmutable) de un dato y las referencias que nos permiten modificarlo en el tiempo de forma segura en lo que respecta a la &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_111"&gt;concurrencia&lt;/span&gt;, etc. La curva de aprendizaje es inversa a la de &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_112"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_53"&gt;Scala&lt;/span&gt;&lt;/span&gt;, muy empinada al principio pero mas leve en cuanto se ha comprendido los principios &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_113"&gt;fundamentales&lt;/span&gt; del paradigma funcional y se ha &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_114"&gt;acostumbrado&lt;/span&gt; uno a los benditos &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_115"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_54"&gt;paréntesis&lt;/span&gt;&lt;/span&gt;. Pero no hay marcha &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_116"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_55"&gt;atras&lt;/span&gt;&lt;/span&gt; una vez que entras en los &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_117"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_56"&gt;paréntesis&lt;/span&gt;&lt;/span&gt;, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_118"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_57"&gt;mmm&lt;/span&gt;&lt;/span&gt;, ¿o tal vez sí?&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;((&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_119"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_58"&gt;TO&lt;/span&gt;&lt;/span&gt; BE &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_120"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_59"&gt;CONTINUED&lt;/span&gt;&lt;/span&gt;))&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-6163367999960057420?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/6163367999960057420/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/09/scala-vs-y-clojure.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6163367999960057420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6163367999960057420'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/09/scala-vs-y-clojure.html' title='Scala &lt;strike&gt;vs&lt;/strike&gt; y Clojure (Round 1)'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-6164550162055265967</id><published>2010-06-14T22:04:00.000+01:00</published><updated>2010-06-14T20:56:29.510+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cloud'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><category scheme='http://www.blogger.com/atom/ns#' term='gae'/><category scheme='http://www.blogger.com/atom/ns#' term='computing'/><category scheme='http://www.blogger.com/atom/ns#' term='appengine'/><title type='text'>Clojure por las nubes (Google AppEngine)</title><content type='html'>&lt;div style="text-align: justify;"&gt;Uno de los campos donde se mas se mueven los programadores en Clojure es en el de la programación web en la &lt;a href="http://es.wikipedia.org/wiki/Cloud_computing"&gt;"nube"&lt;/a&gt;. En concreto &lt;a href="http://code.google.com/intl/es-ES/appengine/"&gt;la alternativa que ofrece google&lt;/a&gt; es bastante popular desde que soporta aplicaciones en java y cualquier lenguaje que pueda ser compilado para la jvm.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La ventaja esta clara, no hay que preocuparse acerca de los recursos de computación necesarios para que tu aplicación funcione, ni anchos de banda, ni cpu o espacio en disco. Puedes desplegar una aplicación de forma gratuita y pagar justo por el espacio de disco, memoria ram y ciclos de cpu que uses a medida que tu aplicación crece. Vamos como si fuera la factura de la luz.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;También tiene su lado malo, la aplicación tiene que ajustarse a las limitaciones sobre las librerias estandar de java y usar las librerias propias de la AppEngine para operaciones básicas asi como la base de datos que ellos te proporcionan. Ademas el kit de desarrollo necesario para desarrollar tu aplicacion no tiene el codigo abierto. Hay que modificar o programar la aplicación para hacerla dependiente de la plataforma.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;En todo caso es una opción bastante atractiva para aplicaciones de prueba e investigación.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;Entre las referencias que pululan por la red la mas atractiva es las de una empresa autogestionada por un grupo de "hackers" amantes del lisp, que han usado Clojure para programar y Google AppEngine para publicar una interesante aplicacion de gestion de "tareas pendientes" orientado a programadores, con ciertos elementos de inteligencia artificial para ayudar a priorizar las tareas y estimar los tiempos que tardaremos en completarlas. La aplicación esta en http://the-deadline.appspot.com&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;En este video la banda nos explica las razones de usar Clojure y GAE:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="width: 425px;" id="__ss_3207276"&gt;&lt;strong style="display: block; margin: 12px 0pt 4px;"&gt;&lt;a href="http://www.slideshare.net/smartrevolution/how-a-clojure-pet-project-turned-into-a-fullblown-cloudcomputing-webapp" title="How a Clojure pet project turned into a full-blown cloud-computing web-app"&gt;How a Clojure pet project turned into a full-blown cloud-computing web-app&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse3207276" height="355" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=thedeadlineinberlin-100217073008-phpapp02&amp;amp;stripped_title=how-a-clojure-pet-project-turned-into-a-fullblown-cloudcomputing-webapp"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed name="__sse3207276" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=thedeadlineinberlin-100217073008-phpapp02&amp;amp;stripped_title=how-a-clojure-pet-project-turned-into-a-fullblown-cloudcomputing-webapp" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="355" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="padding: 5px 0pt 12px;"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/smartrevolution"&gt;smartrevolution&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;En su &lt;a href="http://www.hackers-with-attitude.com/"&gt;blog &lt;/a&gt;ha varios posts que no hay que perderse sobre aspectos técnicos del desarrollo con Clojure y GAE. El que escribe también ha subido el "hello world" de la GAE, &lt;a href="http://clj-guestbook.appspot.com/"&gt;un libro de visitas&lt;/a&gt; básico (&lt;a href="http://github.com/jneira/clj-guestbook"&gt;aqui el codigo&lt;/a&gt;) que combina un servlet en java cogido de la aplicación de demostración que viene con el kit de desarrollo y un "servlet" en clojure usando &lt;a href="http://weavejester.github.com/compojure/"&gt;Compojure &lt;/a&gt;como framework web y &lt;a href="http://github.com/snewman/appengine-clj"&gt;otras librerias&lt;/a&gt; de ayuda para el desarrollo en la GAE.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Asi que si quieres programar en Clojure y ver tu aplicacion por las nubes de forma relativamente sencilla esta puede ser tu opción.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-6164550162055265967?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/6164550162055265967/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/04/clojure-por-las-nubes-google-appengine.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6164550162055265967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6164550162055265967'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/04/clojure-por-las-nubes-google-appengine.html' title='Clojure por las nubes (Google AppEngine)'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-3221235251731264372</id><published>2010-03-23T21:43:00.014Z</published><updated>2011-08-13T14:13:22.147+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='concurrencia'/><category scheme='http://www.blogger.com/atom/ns#' term='inmutabilidad'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><title type='text'>Introducción a Clojure II: inmutabilidad.</title><content type='html'>&lt;quote style="font-style: italic; text-align: justify;"&gt;"Ningun hombre puede cruzar el mismo río dos veces."&lt;/quote&gt;&lt;br /&gt;- Heraclito&lt;br /&gt;&lt;div style="text-align: justify;"&gt;En la &lt;a href="http://javierneirasanchez.blogspot.com/2009/10/introduccion-clojure-lost-in-soup-of.html"&gt;primera entrada introductoria&lt;/a&gt; hablabamos de uno de los obstaculos o reparos que alguien acostumbrado a la programación imperativa de lenguajes herederos del c tiene al acercarse a Clojure: la sintaxis prefija y llena de parentesis. Sin embargo hay otra dificultad a la hora de acercarse a Clojure: la inmutabilidad de los datos y todo lo que ello supone, que no es sino otra forma radicalmente diferente de entender la programación. En Clojure, por defecto, no se puede cambiar el valor asociado a un "simbolo" y se delimita muy claramente las formas en que se puede mutar el valor asociado a una referencia.&lt;br /&gt;Por ejemplo algo tan comun en java como:&lt;br /&gt;&lt;a href="https://gist.github.com/fef3c8eaa3e5b9edbbed#file_gistfile1.java"&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class="java"&gt;int i=0;&lt;br /&gt;while (i&amp;lt;10) i=""&amp;gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;es imposible hacerlo en un lenguaje funcional tal cual ya que no existen las "variables" como se entienden en un lenguaje imperativo (ni tampoco los bucles en el sentido imperativo pero es otra historia). Las variables en Clojure son mas bien como símbolos ligados a valores constantes o a funciones.&lt;br /&gt;&lt;div style="text-align: justify;"&gt;En clojure podemos &lt;span style="font-weight: bold;"&gt;definir&lt;/span&gt; un símbolo e inicializarlo con un valor que ya no puede cambiar, en lo que sería mas cercano a una constante en java.&lt;/div&gt;&lt;pre&gt;;clojure&lt;br /&gt;(def i 10)&lt;br /&gt;// java&lt;br /&gt;final int i=10;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;No parece muy util un lenguaje en que no se puedan transformar los datos y en un lenguaje puramente funcional la unica manera de realizar esa transformación es precisamente mediante funciones. Pero las funciones no modifican los valores pasados por parámetros ni las variables globales, sino que siempre producen valores nuevos. En Clojure no se transforma, solo se crea y se destruye.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Esto suena a herejía, a derroche de memoria y lentitud. Y realmente si que lo es pero actualmente la memoria es barata y los procesadores rapidos y en los lenguajes funcionales modernas ese "crear" nuevos valores esta &lt;a href="http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice/"&gt;optimizado&lt;/a&gt; hasta conseguir un rendimiento bastante razonable.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Otra comparación de código (aunque la comparación no es exacta ni mucho menos, es simplemente para hacerse la idea).&lt;/div&gt;&lt;pre&gt;(defn add [x y] (+ x y))&lt;br /&gt;&lt;br /&gt;Integer add (final Integer x,final Integer y) {&lt;br /&gt;   return new Integer (x.intValue()+y.intValue());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;;o con una lista que tal vez se vea mejor&lt;br /&gt;(def add3 [col] (cons 3 col))&lt;br /&gt;&lt;br /&gt;Collection add3 (final Collection col) {&lt;br /&gt;   ArrayList aux=new ArrayList (col);&lt;br /&gt;   aux.add (new Integer(3));&lt;br /&gt;   return aux;&lt;br /&gt;}&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;Bueno esta muy bien pero por ahora solo parece una limitación respecto a java. En realidad sí que se pueden mutar valores en Clojure pero el punto de vista es el contrario: en Clojure por defecto todo es inmutable y asi nos ahorramos los "final", en java es al reves.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;¿Que se consigue fomentando la inmutabilidad? Pues algo muy valioso: si no mutan el estado de nada exterior a ellas las funciones no tienen efectos laterales (o dicho de otra forma son &lt;a href="http://en.wikipedia.org/wiki/Referential_transparency_%28computer_science%29"&gt;transparentes referencialmente&lt;/a&gt;). El sabio consejo para cualquier lenguaje de limitar el uso de las variables globales aqui se lleva un paso mas adelante: por defecto &lt;span style="font-weight: bold;"&gt;no se pueden&lt;/span&gt; modificar las variables y por tanto no se producen cambios inesperados. Una función siempre devolvera el mismo valor si es llamada con los mismos parámetros independientemente de cuando, en que orden y como se llame y del estado del resto del universo. Si una función falla, falla siempre, y eso que parece una tonteria es el sueño de cualquiera que haya tenido que hacer debug o tests unitarios de una aplicación java o c++. Tampoco parece muy util el no poder producir efectos laterales ya que hay varias acciones que lo necesitan: la entrada y salida de datos, la generacion de numeros aleatorios, etc. En Clojure las funciones pueden producir esos efectos laterales pero de una forma mas delimitada y controlada (aunque sin llegar a la paranoia de Haskell).&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Como conclusion podemos decir que se puede programar en Clojure de forma imperativa si se quiere (al fin y al cabo es un lenguaje multiparadigma) pero el lenguaje fomenta y facilita lo contrario.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Otra ventaja es en el campo de la concurrencia. El complejo análisis (y los horribles bugs que pueden aparecer) del comportamiento de una aplicación con multitud de procesos o hilos de ejecución simultaneos simplemente no es necesario. Los hilos no pueden modificar variables que afecten a los otros porque no pueden modificar las variables.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Hay otras ventajas de este modelo mas simple y matematico de enfocar la programación algunas de las cuales esta &lt;a href="http://www.defmacro.org/ramblings/fp.html"&gt;en este interesante post&lt;/a&gt; sobre la programación funcional.&lt;br /&gt;&lt;br /&gt;Sin embargo no todos los objetivos de una aplicación en el mundo real se pueden conseguir (o al menos facilmente) solo con funciones. Los programadores trabajamos con modelos del mundo real que sufren (o disfrutan) modificaciones a lo largo de una línea temporal. Con Clojure tambien podemos hacerlo pero de forma controlada y automatizada en lo que respecta a la concurrencia. No hay que definir los "locks" manualmente ni analizar donde hay que sincronizar la ejecución de los hilos o procesos, al igual que en java ya no tenemos que preocuparnos de gestionar la memoria manualmente como en c. Pero todo esto da para todo un futuro post.&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-3221235251731264372?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/3221235251731264372/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/03/introduccion-clojure-ii-inmutabilidad.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/3221235251731264372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/3221235251731264372'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/03/introduccion-clojure-ii-inmutabilidad.html' title='Introducción a Clojure II: inmutabilidad.'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-6411551115920545267</id><published>2010-02-24T16:10:00.023Z</published><updated>2010-10-09T22:25:53.756+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='repl'/><category scheme='http://www.blogger.com/atom/ns#' term='ejemplo'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='interactivo'/><title type='text'>Ejemplo básico Clojure y IV: multiplicar números como listas.</title><content type='html'>&lt;ul&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-multiplicar.html"&gt;Ejemplo básico Clojure I.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-ii-multiplicar.html"&gt;Ejemplo básico Clojure II.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-iii-multiplicar.html"&gt;Ejemplo básico Clojure III.&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;Como las masas que siguen este blog son muy tímidas vamos a ponernos manos a la obra para conseguir que la ultima versión de nuestra función para multiplicar listas funcione correctamente. El error es muy básico pero vamos a seguir los pasos para detectarlo y arreglarlo. En Clojure no se sigue el proceso cíclico de codificar-compilar-debuguear-probar tan familiar para los que programamos en lenguajes compilados mas torpes como java. En Clojure (como en todos los lenguajes dinámicos y los estáticos mas modernos) tenemos siempre disponible el &lt;a href="http://en.wikipedia.org/wiki/REPL"&gt;REPL&lt;/a&gt; (&lt;span style="font-style: italic;"&gt;Read-Evaluation-Print-Loop&lt;/span&gt;) que es un entorno interactivo de programación, una consola donde podemos escribir código, que es evaluado por el interprete presentándose el resultado en la consola. De hecho ya la he expuesto en todos los fragmentos tal que así:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&gt; (codigo a evaluar)&lt;br /&gt;resultado&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;El REPL permite una programación dinámica e interactiva ya que tenemos una respuesta inmediata a nuestras pruebas e investigaciones. Vamos a usarla para diagnosticar el problema. Recordemos como era la función:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn multLists [xs ys]&lt;br /&gt;(let [mults (reduce #(cons (multList %2 xs) %1) '() ys)&lt;br /&gt;     despl (apply multDespl mults)]&lt;br /&gt;(listCarry (apply map + despl))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Primero vamos a cambiar la función para tener los resultado intermedios y los almacenamos en una variable auxiliar:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&gt; (defn multLists [xs ys]&lt;br /&gt;(let [mults (reduce #(cons (multList %2 xs) %1) '() ys)&lt;br /&gt;     despl (apply multDespl mults)]&lt;br /&gt;[mults despl (listCarry (apply map + despl))]))&lt;br /&gt;#'mult-listas/multLists&lt;br /&gt;&lt;br /&gt;&gt; (def aux (multLists '(5 6 7 8) '(1 2 3))&lt;br /&gt;#'mult-listas/aux&lt;br /&gt;&lt;br /&gt;&gt; (aux 0)&lt;br /&gt;((1 7 0 3 4) (1 1 3 5 6) (5 6 7 8))&lt;br /&gt;&lt;br /&gt;&gt; (aux 1)&lt;br /&gt;((1 7 0 3 4) (1 1 3 5 6 0) (5 6 7 8 0 0))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Hasta aquí la cosa esta bien, las multiplicaciones parciales son correctas y los desplazamientos a la izquierda también. Vamos a probar el siguiente paso que seria:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&gt; (apply map + (aux 1))&lt;br /&gt;(7 14 10 16 10)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Ooops, aquí esta el error, en lugar de sumar seis elementos ha sumado cinco, si nos fijamos ha sumado los n-esimos elementos de las listas y como la primera solo tiene cinco posiciones ha desechado los últimos elementos de las otras dos. Si comprobamos la documentación de la función map (el énfasis es mio):&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&gt; (doc map)&lt;br /&gt;-------------------------&lt;br /&gt;clojure.core/map&lt;br /&gt;([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 &amp;amp; colls])&lt;br /&gt;Returns a lazy sequence consisting of the result of applying f to the&lt;br /&gt;set of first items of each coll, followed by applying f to the set&lt;br /&gt;of second items in each coll, &lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;until any one of the colls is&lt;br /&gt;exhausted&lt;/span&gt;&lt;span style="font-size:85%;"&gt;. Any remaining items in other colls are ignored. Function&lt;br /&gt;f should accept number-of-colls arguments.&lt;br /&gt;nil&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Para solucionarlo lo primero que se me ha ocurrido es igualar todas las listas añadiendo ceros por la izquierda. Para ello tendremos que calcular la longitud de la lista mas grande y añadir ceros a las demás hasta igualarla. Tal vez haya otra forma mas sencilla de hacerlo, no dudéis en comentar vuestras propuestas. Para igualar las listas necesitaremos otras dos funciones pero candidatas totales a ser reutilizadas mas adelante. Una para añadir n elementos a una lista por la izquierda:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn lpad [lista num elem] (concat (replicate num elem) lista))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La función es casi auto-descriptiva. Para saber la longitud de la lista mas grande nos haremos otra función (aunque ya esta hecha en la &lt;a href="http://github.com/richhickey/clojure-contrib/"&gt;librería auxiliar oficial&lt;/a&gt; de Clojure:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn maxLength [&amp;amp; lst] (apply max (map count lst)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;En esta función vemos el símbolo &lt;span style="font-style: italic;"&gt;&amp;amp;&lt;/span&gt; que hace que la función acepte cualquier numero de parámetros que están disponibles metidos en una lista identificada con el símbolo después de &amp;amp; (lst en este caso). Este símbolo puede estar al final de la lista de parámetros normales. La lista de listas se convierte en una lista de las longitudes de las misma con &lt;span style="font-style: italic;"&gt;map count&lt;/span&gt; y luego usamos &lt;span style="font-style: italic;"&gt;max&lt;/span&gt; para extraer el máximo entre ellos.&lt;br /&gt;&lt;br /&gt;Bueno ya podemos completar la función para que la operación sea correcta:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn multLists [xs ys]&lt;br /&gt;(let [mults (reduce #(cons (multList %2 xs) %1) '() ys)&lt;br /&gt;      despl (apply multDespl mults)&lt;br /&gt;      max (apply maxLength despl)&lt;br /&gt;     lpaded (map #(lpad %1 (- max (count %1)) 0) despl)]&lt;br /&gt;(listCarry (apply map + lpaded))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&gt; (multLists '(5 6 7 8) '(1 2 3))&lt;br /&gt;(6 9 8 3 9 4)&lt;br /&gt;&gt; (numList (multLists '(5 6 7 8) '(1 2 3))&lt;br /&gt;698394&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Ya hemos llegado al final del camino, espero que este sencillo ejemplo os haya picado la curiosidad por Clojure y sus posibilidades.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Teneis el &lt;a href="http://github.com/jneira/clj-desk/blob/master/src/mult-listas.clj"&gt;codigo&lt;/a&gt; del ejemplo en github para que hagais con el lo que querais.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-6411551115920545267?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/6411551115920545267/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-y-iv-multiplicar.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6411551115920545267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6411551115920545267'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-y-iv-multiplicar.html' title='Ejemplo básico Clojure y IV: multiplicar números como listas.'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-7157036023346075789</id><published>2010-02-18T16:47:00.024Z</published><updated>2010-02-24T21:36:39.298Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='iterate'/><category scheme='http://www.blogger.com/atom/ns#' term='ejemplo'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='evaluacion perezosa'/><category scheme='http://www.blogger.com/atom/ns#' term='introduccion'/><title type='text'>Ejemplo básico Clojure III: multiplicar números como listas.</title><content type='html'>&lt;ul&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-multiplicar.html"&gt;Ejemplo básico Clojure I.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-ii-multiplicar.html"&gt;Ejemplo básico Clojure II.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-y-iv-multiplicar.html"&gt;Ejemplo básico Clojure y IV.&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;Ya tenemos nuestras dos funciones de conversión entre numero y listas y podemos pensar en realizar operaciones. En este caso tenemos que trabajar con dos listas y hacer la multiplicación tal como la haríamos con papel y lápiz. Es decir multiplicar todos los elementos de la lista por cada uno de los elementos de la otra, sumando el acarreo y sumar todos los productos desplazando una posición a la izquierda cada vez.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;De la descripción de lo que queremos podemos deducir las funciones que nos harán falta. En primer lugar necesitaremos unas funciones que nos sumen listas de dígitos. Lo que es la simple suma de los elementos es bastante directa:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&gt; (map + '(4 5 6) '(7 8 9))&lt;br /&gt;'(11 13 15)&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Map es otra función básica en cualquier lenguaje funcional y aplica una función a cada uno de los elementos de una lista devolviendo la lista resultante. En Clojure si hay varias listas (como en este caso) aplica la función a todos los n-esimos elementos de cada una de las listas. El ejemplo anterior se convertiría en algo así:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;((+ 4 7) (+ 5 8) (+6 9))&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La cuestión es que no nos vale ya que no queremos (11 13 15) que se nos convertirá en 111315. Hace falta, al igual que cuando sumamos a la antigua usanza dejar el dígito de la unidad y sumar el dígito de la decena al siguiente termino de la suma: (1 2 4 5). Como hemos empezado a describir la resolución "de abajo a arriba", o sea de las funciones mas simples a las complejas que las usan nos ocuparemos de la suma con acarreo. Para construir la nueva lista usaremos de nuevo &lt;span style="font-style: italic;"&gt;reduce&lt;/span&gt;, para recorrer todos los elementos de la lista e ir construyendo la nueva lista pasando el acarreo y la lista de un elemento a otro.&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn listCarry [xs]&lt;br /&gt;&amp;nbsp;(let [[x,xs] (reduce carry [0 '()] (reverse xs))]&lt;br /&gt;&amp;nbsp;&amp;nbsp;(if (zero? x) xs (cons x xs))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Usamos de elemento intermedio un vector de dos posiciones &lt;span style="font-style: italic;"&gt;[acarreo '(lista a devolver)]&lt;/span&gt;. La función que coge ese dato y nos devuelve el siguiente es:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn carry [acc x]&lt;br /&gt;&amp;nbsp;(let [s (+ x (acc 0)) [d r] (div s 10)]&lt;br /&gt;&amp;nbsp;[d (cons r (acc 1))]))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&gt; (carry [0 ()] 15)&lt;br /&gt;[1 (5)]&lt;br /&gt;&gt; (carry [1 '(5)] 13)&lt;br /&gt;[1 (4 5)]&lt;br /&gt;&gt; (carry [1 '(4 5)] 11)&lt;br /&gt;[1 (2 4 5]&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La función &lt;span style="font-style: italic;"&gt;listCarry&lt;/span&gt; si el ultimo acarreo es cero nos devuelve la lista construida y si no se lo añade antes de devolverla.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&gt; (listCarry '(11 13 15))&lt;br /&gt;(1 2 4 5)&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Ya podemos atacar la siguiente función que seria multiplicar una lista de dígitos por un solo elemento base de la que queremos. Simplemente aplicaremos una función anónima que multiplica por el elemento en cuestión a todos los elementos de la lista con &lt;span style="font-style: italic;"&gt;map&lt;/span&gt;, y le pasaremos a la lista resultante la función &lt;span style="font-style: italic;"&gt;listCarry&lt;/span&gt;:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn multList [m lst]&lt;br /&gt;  (listCarry (map #(* %1 m) lst)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&gt;  (multList 2 '(5 6 7 8))&lt;br /&gt;(1 1 3 5 6)&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Bueno la primera implementación de la multiplicación entre listas esta muy cerca, parecería que solo hay que recorrer los elementos de un lista, multiplicar la otra por cada uno de ellos y sumar las listas resultantes. Sin embargo ya podemos prever que como mínimo tendremos que desplazar cada una de las multiplicaciones parciales una "posición" hacia la izquierda mas que la anterior. Al ser sumas ese desplazamiento podemos traducirlo añadiendo ceros por la derecha. Podríamos o bien añadir los ceros a la vez que vamos haciendo las multiplicaciones o añadir los que toquen en la lista resultante. Una función general independiente que añada ceros por la derecha podría ser utilizada mas adelante así que vamos a elegir esta ultima opción:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn multDespl [&amp;amp; lst]&lt;br /&gt;&amp;nbsp;(map concat lst (iterate #(cons 0 %1) '())))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Esta funcion se aprovecha de otra poderosa característica de Clojure (compartida con Haskell): &lt;a href="http://clojure.org/lazy"&gt;la evaluación "perezosa"&lt;/a&gt;. Muchas funciones en Clojure nos devuelven una secuencia que no se evalúa en el mismo momento de ser llamada la función. La evaluación de un elemento de la secuencia se hace cuando es necesario y no antes. Eso permite que podamos escribir funciones que representen secuencias infinitas en potencia, con la seguridad de que solo se computara hasta el elemento que necesitemos. La ultima función usa la evaluación perezosa en&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(iterate #(cons 0 %1) '())&lt;br /&gt;&lt;/pre&gt;La función &lt;span style="font-style: italic;"&gt;iterate&lt;/span&gt; aplica una función a un valor inicial (una lista vacia en nuestro caso) y vuelve a aplicarla sobre el resultado anterior una y otra vez hasta el infinito. Obviamente un ordenador no puede manejar listas infinitas, así que tendremos que decirle hasta donde queremos usarla, por ejemplo con la función take que "toma" los elementos que queramos de una secuencia.&lt;br /&gt;&lt;br /&gt;&gt; (take 4 (iterate #(cons 0 %1) ())&lt;br /&gt;((0) (0 0) (0 0 0) (0 0 0 0) (0 0 0 0 0))&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Bien ya podemos intuir lo que hace la función de desplazar a la izquierda: une cada una de las listas que representan las multiplicaciones parciales a cada una de las listas con ceros de nuestro &lt;span style="font-style: italic;"&gt;iterate&lt;/span&gt;:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&gt; (multDespl '(1 2 3) '(1 2) '(1))&lt;br /&gt;((1 2 3 0) (1 2 0 0) (1 0 0 0))&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Bien, ya parece que tenemos nuestros ladrillos para construir la función principal:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn multLists [xs ys]&lt;br /&gt;&amp;nbsp;(let [mults (reduce #(cons (multList %2 xs) %1) '() ys)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;despl (apply multDespl mults)]&lt;br /&gt;&amp;nbsp;(listCarry (apply map + depls))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La función define en un &lt;span style="font-style: italic;"&gt;let&lt;/span&gt; dos resultados intermedios, en &lt;span style="font-style: italic;"&gt;mults&lt;/span&gt; las multiplicaciones parciales resultantes de multiplicar la lista &lt;span style="font-style: italic;"&gt;xs&lt;/span&gt; por cada uno de los elementos de &lt;span style="font-style: italic;"&gt;ys&lt;/span&gt;. En &lt;span style="font-style: italic;"&gt;despl&lt;/span&gt; rehacemos la lista con los desplazamientos hacia la izquierda. Finalmente en el cuerpo de la función sumamos todas las listas intermedias y le pasamos la función &lt;span style="font-style: italic;"&gt;listCarry&lt;/span&gt;. Sin embargo si probamos la función:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&gt; (multLists '(5 6 7 8) '(1 2 3))&lt;br /&gt;(8 5 1 7 0)&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;¡Argh! Nuestro gozo en un pozo, la solución ni se acerca a la solución real (si la calculadora de Google no falla tendría que ser (6 9 8 3 9 4). Os doy unos días para averiguar por qué ... &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-7157036023346075789?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/7157036023346075789/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-iii-multiplicar.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/7157036023346075789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/7157036023346075789'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-iii-multiplicar.html' title='Ejemplo básico Clojure III: multiplicar números como listas.'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-6764605334006251311</id><published>2010-02-17T16:25:00.013Z</published><updated>2010-10-09T22:13:54.079+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='anonima'/><category scheme='http://www.blogger.com/atom/ns#' term='reduce'/><category scheme='http://www.blogger.com/atom/ns#' term='ejemplo'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='introduccion'/><category scheme='http://www.blogger.com/atom/ns#' term='funcion'/><title type='text'>Ejemplo básico Clojure II: multiplicar números como listas.</title><content type='html'>&lt;ul&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-multiplicar.html"&gt;Ejemplo básico Clojure I.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-iii-multiplicar.html"&gt;Ejemplo básico Clojure III.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-y-iv-multiplicar.html"&gt;Ejemplo básico Clojure y IV.&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;En el &lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-multiplicar.html"&gt;episodio anterior&lt;/a&gt; conseguimos la función que nos convierte un número en la lista de sus dígitos:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&gt; (numList 12345)&lt;br /&gt;(1 2 3 4 5)&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Nos faltaría el proceso inverso para tener la cosa completa. En este caso partimos de una lista de elementos y tenemos que "reducirla" a uno solo. La implementación cruda se puede hacer recursivamente, extrayendo cada uno de los dígitos y haciendo la operación inversa a la función anterior, es decir, empezando por el último, multiplicar cada elemento por diez y sumarlo al siguiente:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn listNum [l]+&lt;br /&gt;(let [x (last l) xs (butlast l)]&lt;br /&gt;   (if (nil? x) 0 (+ x (* 10 (listNum xs))))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Como en cualquier aproximación recursiva primero establecemos el caso trivial que es cuando ya no haya mas elementos en la lista (o sea cuando sea "nil" o nulo el elemento extraido de la lista). Entonces devolveremos el valor básico 0. Luego construimos la llamada de "dentro a afuera", como si fuera una muñeca rusa. La recursión puede ser un poco confusa al principio hasta que la mente abandona los for, while y compañía. En este caso no podemos usar &lt;span style="font-style: italic;"&gt;recur&lt;/span&gt; ya que la llamada recursiva no es la ultima expresión evaluada en la funcion.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;La ejecución de (listNum '(1 2 3)) se podria rastrear poniendo todas las llamadas recursivas a la vez así:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;(+ 3 (* 10 (+ 2 (* 10 (+ 1 (* 10 0))))))&lt;br /&gt;(+ 3 (* 10 (+ 2 (* 10 (1)))))&lt;br /&gt;(+ 3 (* 10 (+ 2 (10))))&lt;br /&gt;(+ 3 (* 10 (12)))&lt;br /&gt;(+ 3 120)&lt;br /&gt;123&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La operacion de recorrer una lista e ir creando un valor acumulativo aplicando una funcion a cada elemento de la lista es algo tan habitual que hay una función especializada en ello: &lt;span style="font-style: italic;"&gt;&lt;a href="http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/reduce"&gt;reduce&lt;/a&gt;&lt;/span&gt;, que precisamente "reduce" una lista a un unico valor aplicando una función a cada uno de los elementos de la lista y al valor acumulado anterior. Esta función entra dentro de las llamadas de "orden superior" ya que o bien toman otras funciones como parametro, bien devuelven otra función o ambas cosas. La firma de &lt;span style="font-style: italic;"&gt;reduce&lt;/span&gt; sería:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;(reduce funcionAcumuladora valorInicial listaAProcesar)&lt;br /&gt;&lt;br /&gt;Usandola nuestra función quedaría así:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defn listNum [lst] (reduce #(+ %2 (* 10 %1)) 0 lst))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Aparece aqui algo muy interesante: una función anónima representada por #(...). Dentro de la misma podemos hacer referencia a los parametros en orden con %1,%2,etc.&lt;br /&gt;La traducción de la función anónima a una con nombre sería:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn acumulador [p1 p2] (+ p2 (* 10 p1)))&lt;br /&gt;(defn listNum [lst] (reduce acumulador 0 lst))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Bueno con nuestras funciones de conversión ya podemos empezar a pensar en como multiplicaremos dos números como listas de dígitos, pero sera en &lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-iii-multiplicar.html"&gt;la siguiente entrada&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-6764605334006251311?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/6764605334006251311/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-ii-multiplicar.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6764605334006251311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6764605334006251311'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-ii-multiplicar.html' title='Ejemplo básico Clojure II: multiplicar números como listas.'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-6077969493341264523</id><published>2010-02-15T21:25:00.044Z</published><updated>2010-02-24T21:06:19.604Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='let'/><category scheme='http://www.blogger.com/atom/ns#' term='ejemplo'/><category scheme='http://www.blogger.com/atom/ns#' term='recur'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='introduccion'/><title type='text'>Ejemplo básico Clojure I: multiplicar números como listas.</title><content type='html'>&lt;ul&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-ii-multiplicar.html"&gt;Ejemplo básico Clojure II.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-iii-multiplicar.html"&gt;Ejemplo básico Clojure III.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-y-iv-multiplicar.html"&gt;Ejemplo básico Clojure y IV.&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;(Si queréis poner en practica el ejemplo de esta serie de posts &lt;a href="http://en.wikibooks.org/wiki/Clojure_Programming/Getting_Started"&gt;aquí&lt;/a&gt; tenéis unas instrucciones  precisas de como instalar y los primeros pasos  con Clojure .)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hace poco me examine de la asignatura de &lt;a href="http://www.lsi.uned.es/pd/"&gt;Programación Declarativa en la UNED&lt;/a&gt; que consiste en gran parte en programar en &lt;a href="http://www.haskell.org/"&gt;Haskell&lt;/a&gt;. Tal vez algun día me ocupe de este lenguaje, funcional como Clojure pero con una sintaxis mas barroca y todo un universo propio en el que se intenta mantener la pureza funcional y la referencia transparencial a base encerrar lo impuro en unas carceles llamadas &lt;a href="http://www.haskell.org/haskellwiki/Monads"&gt;monadas&lt;/a&gt;. Un lenguaje fascinante pero tal vez un paso mas alejado del mundo de los negocios que otros lenguajes funcionales modernos como clojure, scala o erlang.&lt;br /&gt;Uno de los ejercicios que se proponían para practicar era el siguiente, extraido del &lt;a href="http://people.cs.uu.nl/jeroen/courses/fp-sp.pdf"&gt;manual&lt;/a&gt; que seguíamos en la asignatura: dado dos números representados como una lista de sus dígitos, declarar una función que devuelva en el mismo formato el resultado de multiplicarlos, así como las funciones para convertir un numero en una lista en ese formato y otra que haga la operación inversa. La ventaja de representar así los números es que puedes sobrepasar el límite establecido para los tipos numéricos enteros habituales.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Ejemplo de lo que queremos:&lt;br /&gt;&lt;br /&gt;-&gt;(def x (numList 12345))&lt;br /&gt;(1 2 3 4 5)&lt;br /&gt;&lt;br /&gt;-&gt;(def y (numList 12))&lt;br /&gt;(1 2)&lt;br /&gt;&lt;br /&gt;-&gt;(mult x y)&lt;br /&gt;(1 4 8 1 4 0)&lt;br /&gt;&lt;br /&gt;-&gt;(listNum (mult x y))&lt;br /&gt;148140&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;En esta primera entrada nos pondremos con las función auxiliar que nos convierten un número en una lista. Para conseguir nuestra lista de dígitos habrá que dividir el número por 10, acumular el resto en la lista y volver a realizar la operación con el cociente de la división anterior hasta que la división nos de 0:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;12345/10 -&gt; cociente:1234 restos:(5)&lt;br /&gt;1234/10-&gt; 123 (4 5)&lt;br /&gt;123/10-&gt; 12 (3 4 5)&lt;br /&gt;12/10-&gt; 1 (2 3 4 5)&lt;br /&gt;1/10-&gt; 0 (1 2 3 4 5)&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La descripción de la función ya nos da la pista de que usar la recursión será la solución mas elegante y ajustada. Como vamos a usar el resto y el cociente de la división entera nos haremos una función auxiliar que nos devuelva ambos resultados en un vector:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn div [x y] [(quot x y) (rem x y)])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;-&gt; (div 5 3)&lt;br /&gt;[1 2]&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;La primera aproximación usando la recursión tal cual será hacernos una función auxiliar &lt;span style="font-style: italic;"&gt;iNumList&lt;/span&gt; que irá haciendo las divisiones y acumulando los restos y que nos devolverá la lista acumulada cuando la división sea igual a 0, y llamar a esa función con una lista vacia inicial desde la función principal:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn numList [num] (iNumList () num))&lt;br /&gt;&lt;br /&gt;(defn iNumList [acc x]&lt;br /&gt;(let [[cociente resto] (div x 10) lista (cons resto acc)]&lt;br /&gt;(if (zero? cociente) lista (iNumList lista cociente))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Veamos la función &lt;span style="font-style: italic;"&gt;iNumList&lt;/span&gt;. En primer lugar se usa &lt;span style="font-style: italic;"&gt;let&lt;/span&gt;. Habria mucho que decir de esta &lt;a href="http://clojure.org/special_forms"&gt;forma especial&lt;/a&gt; que forma parte del nucleo mismo de Clojure pero basicamente enlaza símbolos con expresiones o valores constantes dentro de un vector y los pone a disposición de las expresiones que siguen a ese vector. En cada uno de los enlaces estan también disponibles los símbolos anteriores. &lt;span style="font-style: italic;"&gt;Let&lt;/span&gt; soporta el enlace basado en la estructura abstracta (o "destructuracion") de la expresion a enlazar. Consiste en que podemos usar la estructura del dato para realizar el enlace. Se ve mejor con un ejemplo:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;-&gt; (let [&lt;span style="font-weight: bold;"&gt;[x,y] [10,2]&lt;/span&gt; z (* x y)] (list x 'por y 'igual 'a z))&lt;br /&gt;(10 por 2 igual a 20)&lt;br /&gt;&lt;br /&gt;Gracias a la destructuración del vector [10,2] usando su misma estructura en los simbolos [x,y] nos hemos ahorrado el tener que hacer:&lt;br /&gt;&lt;br /&gt;-&gt;(let [&lt;span style="font-weight: bold;"&gt;v [1,2] x (v 0) y (v 1)&lt;/span&gt; z (* x y)] (list x 'por y 'igual 'a z))&lt;br /&gt;(10 por 2 igual a 20)&lt;br /&gt;&lt;br /&gt;En java no existe la destructuracion y la traduccion al mismo del ultimo codigo mas o menos seria:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Object[] ejemploLet () {&lt;br /&gt;int[] v=new int[] {10,2};&lt;br /&gt;int x=v[0],y=v[1],z=x*y;&lt;br /&gt;return new Object[] {new Integer (x),"por",new Integer (y),&lt;br /&gt;               "es",new Integer (z)};&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Volviendo a la función vemos que gracias a &lt;span style="font-style: italic;"&gt;let&lt;/span&gt; tenemos nuestro resto, cociente y la lista en la que estamos acumulando los restos. Para ir construyendo la lista se usa &lt;span style="font-style: italic;"&gt;cons&lt;/span&gt; que inserta un elemento en la cabeza de una lista. Usando &lt;span style="font-style: italic;"&gt;if&lt;/span&gt; hacemos la recursión en el caso de que no sea 0 el cociente llamando a la misma función con el nuevo cociente.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Sin embargo el uso de la recursión tiene un pequeño problema ya que la parte de la memoria que se usa para almacenar los valores de cada llamada (&lt;a href="http://es.wikipedia.org/wiki/Pila_de_llamadas"&gt;stack&lt;/a&gt;) es mas limitada que la memoria normal donde se almacenan los datos de un programa (&lt;a href="http://es.wikipedia.org/wiki/Heap"&gt;heap&lt;/a&gt;). Para numeros muy, muy grandes la llamada provocaría el famoso &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/StackOverflowError.html"&gt;&lt;span style="font-style: italic;"&gt;java.lang.StackOverflowError&lt;/span&gt;&lt;/a&gt;. Para evitarlo en Clojure usa una &lt;a href="http://en.wikipedia.org/wiki/Tail_call_optimization"&gt;forma especial&lt;/a&gt; de hacer la recursión optimizada , consiguiendo la efectividad de los lenguajes imperativos sin perder la elegancia de la recursión. Esta forma especial se consigue con &lt;span style="font-style: italic;"&gt;recur&lt;/span&gt; y tiene una importante limitación: debe estar en la última expresión evaluada de la función. Asociandolo a otra forma especial, &lt;span style="font-style: italic;"&gt;loop&lt;/span&gt; podemos hacer una recursión segura y evitarnos la función auxiliar incrustandola dentro de la principal:&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;(defn numList [x]&lt;br /&gt;(loop [acc () sig x]&lt;br /&gt;(let [[cociente resto] (div sig 10) lista (cons resto acc)]&lt;br /&gt;(if (zero? cociente) lista (recur lista cociente)))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-style: italic;"&gt;Loop&lt;/span&gt; marca el punto sobre el que se hace la recursión y enlaza en cada nueva llamada los parametros en un &lt;span style="font-style: italic;"&gt;let&lt;/span&gt; implicito, iniciandolo con los valores () y el número original en la primera llamada.&lt;br /&gt;&lt;br /&gt;En &lt;a href="http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-ii-multiplicar.html"&gt;siguientes&lt;/a&gt; posts seguiremos desarrollando este ejemplo introductorio.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-6077969493341264523?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/6077969493341264523/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-multiplicar.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6077969493341264523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6077969493341264523'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2010/02/ejemplo-basico-clojure-multiplicar.html' title='Ejemplo básico Clojure I: multiplicar números como listas.'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-306238420822453074</id><published>2010-02-11T20:30:00.007Z</published><updated>2011-08-13T14:59:15.140+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sintaxis'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='introduccion'/><title type='text'>Introducción a Clojure: "Lost In a Soup of Parenthesis"</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;quote style="font-style: italic;"&gt;&lt;em&gt;"Merece la pena aprender Lisp por la intensa experiencia de iluminación que tendras cuando finalmente lo domines; esa experiencia te hara un mejor programador para el resto de tus dias, aunque nunca vayas a usarlo demasiado."&lt;/quote&gt;&lt;/em&gt;&lt;br /&gt;&lt;quote style="font-style: italic;"&gt;&lt;/quote&gt;&lt;/div&gt;- Eric Raymond &lt;a href="http://catb.org/~esr/faqs/hacker-howto.html"&gt;Como ser un hacker&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Puede parecer exagerado y poco pragmático pero si pongo la cita es porque mi experiencia como aprendiz de un dialecto del Lisp coincide plenamente con lo que dice. Lisp parece un alien de otra galaxia comparado con la mayoria de los lenguajes mas populares de la actualidad, dominados en mayor o menor medida (cada vez menos) por la sintaxis del lenguaje c y por el estilo de programar imperativo.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Como lo primero que extraña o repele del lenguaje es su sintaxis, es decir su apariencia, me ha parecido oportuno profundizar en el por qué de los paréntesis y como, si los vuelves a mirar con un poco de atención, cobran sentido. No se tarda mucho, ayudado por algun editor que te vaya marcando los inicios y cierres de los mismos, en olvidarlos y entonces solo te queda disfrutar de las virtudes de esa extraña sintaxis.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;quote style="font-style: italic;"&gt;&lt;em&gt;"Si quieres engañar a tu jefe para conseguir que te deje programar en Lisp, le puedes contar que es XML"&lt;/quote&gt;&lt;/em&gt;&lt;/div&gt;-Paul Graham &lt;a href="http://www.paulgraham.com/icad.html"&gt;La venganza de los "nerdos"&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Y no solo es un "engaño", xml ha reinventado la esencia del Lisp de que el &lt;a href="http://es.wikipedia.org/wiki/Homoiconicidad"&gt;"codigo es igual a los datos"&lt;/a&gt; (code as data), lo que hace que el codigo en Lisp sea tan maleable y extensible, a la vez que minimalista, que cualquier capacida de metaprogramación de los lenguajes actuales palidezca al lado de el.&lt;br /&gt;Esta comparación con el xml ha sido desarrollada para introducir a los no habituados al Lisp &lt;a href="http://manning.com/rathore/"&gt;en uno de los libros&lt;/a&gt; que existen sobre el lenguaje y también, aplicado al Lisp en general en esta &lt;a href="http://www.defmacro.org/ramblings/lisp.html"&gt;pagina&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Voy a intentar trasladar esa misma ruta del xml al Lisp para aquellos que sienten curiosidad de por que puñetas se le ocurrió a alguien diseñar un lenguaje de programación tan extraño.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Casi todo el mundo conoce &lt;a href="http://es.wikipedia.org/wiki/XML"&gt;XML&lt;/a&gt;, una forma estandar de representar datos que ha permitido una gran flexibilidad a la hora de integrar lenguajes y plataformas muy diferentes, sirviendo de lenguaje de definición de datos de tecnologias tan usadas como AJAX o los servicios web, asi como para representar la configuracion de casi todas las frameworks de java. Tambien ha sido usado como lenguaje de programación (por ejemplo &lt;a href="http://en.wikipedia.org/wiki/Xslt"&gt;XSLT&lt;/a&gt;) y es ahí donde empieza nuestro camino.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Empezaremos por este sencillo codigo en c:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1143842.js?file=add.c"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Vamos a imaginar que tenemos un lenguaje escrito en xml y vamos a traducir la sintaxis de c al mismo (de hecho ya existe un &lt;a href="https://java2xml.dev.java.net/"&gt;libreria &lt;/a&gt;que te permite tranformar codigo java en xml y &lt;a href="http://www.gccxml.org/HTML/Index.html"&gt;otra &lt;/a&gt;para c):&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1143842.js?file=funcion1"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Bueno parece bastante razonable el resultado. Ahora podemos imaginar un poco lo que podríamos hacer con este xml antes de volver a transformarlo en código, compilarlo y ejecutarlo. Podríamos transformarlo de forma automática con xslt (por ejemplo en otro lenguaje), analizarlo en busca de mejoras, guardarlo o enviarlo a un servicio web que nos lo compilara. Podríamos buscar patrones sintácticos en el lenguaje que se repitieran una y otra vez y hacer transformaciones automáticas en función de etiquetas para ahorrarnos escribir código.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Dando un paso mas podriamos establecer una sintaxis uniforme para todos lenguajes en el que el xml representara el &lt;a href="http://es.wikipedia.org/wiki/%C3%81rbol_de_sintaxis_abstracta"&gt;AST&lt;/a&gt; casi directamente. Estos lenguajes no necesitarian tranformar su codigo en un arbol sintáctico abstracto intermedio sino en XML, que es estandar y maleable de forma automatizada.&lt;/div&gt;Si miramos con atencion el xml, ¿que diríamos?, ¿son datos o es código?, ¡Las dos cosas de forma intercambiable!&lt;br /&gt;&lt;div style="text-align: justify;"&gt;El XML esta muy bien pero tiene un pequeño defecto, rodea a lo que nos interesa de muchos carácteres lo que lo hace engorroso de escribir, de leer y enlentece su envío a través de cualquier canal de comunicación. Por eso se esta empezando a sustituir en las aplicaciones web por &lt;a href="http://es.wikipedia.org/wiki/JSON"&gt;JSON&lt;/a&gt;, que es igual de legible pero mucho mas breve: en la programación casi siempre menos es mas.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Vamos a intentar cambiar el xml para hacerlo mas breve. Primero usaremos solo un '&amp;lt;' para iniciar las etiquetas xml y usaremos un simple '&amp;gt;' para representar los cierres de las etiquetas. El xml quedaria asi:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1143842.js?file=funcion2"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Bien, ahora vamos a establecer unas reglas para ahorrarnos mas caracteres en plan "&lt;a href="http://en.wikipedia.org/wiki/Convention_over_configuration"&gt;convención sobre configuración&lt;/a&gt;": vamos a suponer que el que nos va a evaluar el definir una función es un tio listo y va a poder inferir el tipo que devuelve la función del retorno que esta dentro y que vamos a establecer obligatorio para una función. Vamos a establecer tambien que el primer simbolo despues de la marca de definir la función es su nombre ya que también es obligatorio. Los argumentos siempre iran justo despues del nombre y entre corchetes y su tipo también será inferido en tiempo de ejecución. La cosa quedaria así:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1143842.js?file=funcion3"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;El "cuerpo" también vamos a darlo por supuesto y obligatorio para toda definición de función y dentro de la misma siempre el ultimo elemento será lo que se devuelve (si hay varios, en nuestro caso solo hay uno) así que nos lo podemos ahorrar. Al llamar a otra función lo primero sera siempre su nombre y lo que hay detras siempre sus argumentos en el mismo orden en el que estan definidos. Por ultimo acortaremos un poco los nombres: a definir-función lo llamaremos &lt;span style="font-style: italic;"&gt;defn&lt;/span&gt; y para sumar usaremos el caracter '+'. La cosa&lt;br /&gt;quedaría así:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1143842.js?file=funcion4"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Bueno parece que ya llegamos al final del camino. Personalmente '&amp;lt;' y '&amp;gt;' me parecen demasiado puntiagudos y ademas si queremos usarlos como "menos que" y "mayor que" igual hay problemas así que vamos a sustituirlo por... sí señor, por esos paréntesis tan denostados:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1143842.js?file=funcion.clj"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Hemos acortado bastante el código (tranformandolo en Clojure) y sin embargo seguimos teniendo las ventajas del xml. La definición de una función (y la llamada a la misma) es una lista que puede tener sublistas, es decir, una estructura de datos que podemos transformar, guardar, enviar a nuestro antojo antes de ser evaluada por el interprete. Más técnicamente podríamos decir que es una representación casi directa del arbol abstracto sintáctico misterioso que esta dentro de cualquier compilador y que o bien no se puede ver ni tocar o hay que hacerlo a traves de algun intermediario. En Clojure escribimos el arbol sintactico a la vez que el codigo y eso nos da el poder casi total sobre la sintaxis del lenguaje.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Bien pongamos un ejemplo de lo que se puede hacer gracias a los paréntesis. Asi es como se puede insertar una fila en una tabla con clojure:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1143842.js?file=insert.clj"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Quienquiera que haya programado con jdbc habra acabado harto de repetir los bloques try-catch y de abrir y cerrar conexiones. El código de mas arriba en java sería:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1143842.js?file=insert.java"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Espero que al menos hayais visto el posible sentido de los paréntesis y os animeis a mirar de nuevo Clojure con un poco menos de extrañeza.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-306238420822453074?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/306238420822453074/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/10/introduccion-clojure-lost-in-soup-of.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/306238420822453074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/306238420822453074'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/10/introduccion-clojure-lost-in-soup-of.html' title='Introducción a Clojure: &quot;Lost In a Soup of Parenthesis&quot;'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-2455577895434544896</id><published>2009-11-14T14:31:00.016Z</published><updated>2010-02-12T14:04:11.936Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='multilenguaje'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><category scheme='http://www.blogger.com/atom/ns#' term='jvm'/><title type='text'>Sobre Java II (o ¿Esta muerto java?)</title><content type='html'>&lt;span style="text-align: justify;"&gt;&lt;p style="text-indent: 3em;"&gt; En el anterior post intentaba explicar porque no se me había ocurrido escribir sobre java. Al hacerlo realizaba una critica sobre el aduciendo que era lenguaje obsoleto e incapaz de adaptarse a los cambios debido su exito. Se podría deducir mis palabras que me adhiero al creciente numero de los que se apuntan al lema "java is dead" (213.000 resultados en google). Algunos  van  mas allá y se cuestionan no solo java sino la misma jvm y dando un paso el mismo paradigma de la  programación  orientada a  objetos cuyos lenguajes estrellas han sido precisamente java y c++.&lt;br /&gt;&lt;/p&gt;&lt;p style="text-indent: 3em;"&gt;En este tema soy mas bien &lt;span&gt;pragmático&lt;/span&gt;, sobre todo cuando hablamos de hacer negocios con un lenguaje de programación. Como comentaba en el post anterior java es muy utilizado en la empresa y no puede haber tanta gente cuyo objetivo principal es ganar dinero equivocada. Ha sido &lt;span&gt;así&lt;/span&gt; hasta ahora y lo sera durante mucho tiempo &lt;span&gt;así&lt;/span&gt; que no &lt;span&gt;temáis&lt;/span&gt; los javahispanicos que tenemos java para rato, nos guste o no.&lt;br /&gt;&lt;/p&gt;&lt;p style="text-indent: 3em;"&gt;Sin embargo tampoco se puede ignorar los cambios que se &lt;span&gt;están&lt;/span&gt; sucediendo que han hecho que se empiecen a elegir otros lenguajes en algunos campos de la empresa debido a que se ajustan mejor a su problemática especifica. Por ejemplo twitter ya se hizo en su &lt;span&gt;día&lt;/span&gt; en ruby, y no hace mucho cambio la parte "backend" &lt;a href="http://www.artima.com/scalazine/articles/twitter_on_scala.html"&gt;a scala&lt;/a&gt;, manteniendo ruby para la parte web.  En el mundo de la jvm, claramente influido por la pionera en este sentido plataforma .net, se esta afianzando &lt;a href="http://www.defgroovy.com/2009/08/delivering-business-value-through.html"&gt;la idea del paradigma del multilenguaje&lt;/a&gt;, por el que los lenguajes se convierten, como las &lt;span&gt;librerías&lt;/span&gt;, en herramientas disponibles para poder elegir la mas adecuada en &lt;span&gt;función&lt;/span&gt; del problema a resolver. &lt;span&gt;También&lt;/span&gt; es verdad que añades &lt;a href="http://bill.burkecentral.com/2009/07/20/polyglotism-is-the-worst-idea-i-ever-heard/"&gt;otras fuentes de problemas&lt;/a&gt; entre ellas la interoperatibilidad entre los diferentes lenguajes. En ese sentido java &lt;span&gt;podría&lt;/span&gt; convertirse con el tiempo en el lenguaje de bajo nivel &lt;span&gt;básico&lt;/span&gt; de la jvm, primitivo &lt;span&gt;rápido&lt;/span&gt; y lo mas cercano al bytecode. O sea lo que seria c para las plataformas unix/linux y windows lo sería java para la plataforma  jvm. La verdad es que no me imagino un servidor j2ee programado en groovy o en jython (mm tal vez si en scala). Stuart Halloway &lt;span&gt;escribió&lt;/span&gt; una &lt;a href="http://blog.thinkrelevance.com/2008/9/24/java-next-overview"&gt;serie de posts&lt;/a&gt; sobre el tema que no se pueden pasar por alto respecto a este tema.&lt;/p&gt;&lt;p style="text-indent: 3em;"&gt;La jvm no es igual a java y &lt;a href="http://stuartsierra.com/2009/09/22/its-about-the-platform"&gt;tiene ventajas &lt;/a&gt;que han hecho por ejemplo que Rick Hickey y otros la hayan usado como plataforma destino de su lenguaje en lugar de ponerse a a hacer compiladores en c para cada uno de los sistemas operativos mas usados. Es independiente del hardware, esta muy optimizada a nivel de compilador y probada en &lt;span&gt;ámbitos&lt;/span&gt; donde un fallo puede costar mucho dinero (aunque siempre queden flecos) y tienes miles de lineas de &lt;span&gt;código&lt;/span&gt; y &lt;span&gt;librerías&lt;/span&gt; disponibles para hacer casi cualquier cosa en casi cualquier &lt;span&gt;ámbito&lt;/span&gt; de la programación. Cierto es que se creo ligada a java (y por tanto la &lt;span&gt;tradición&lt;/span&gt; imperativa de c y c++) y eso ha hecho por ejemplo que algunos &lt;span&gt;desconfíen&lt;/span&gt; del &lt;span&gt;carácter&lt;/span&gt; innovador de scala y clojure ya que por debajo siempre arrastraran los limites y defectos de la misma jvm. Sin embargo hay que ser demasiado puro para ignorar las ventajas de escribir en un lenguaje compatible con todo el codigo disponible en java o en c#.&lt;/p&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-2455577895434544896?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/2455577895434544896/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/11/sobre-java-ii-o-esta-muerto-java.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/2455577895434544896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/2455577895434544896'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/11/sobre-java-ii-o-esta-muerto-java.html' title='Sobre Java II (o ¿Esta muerto java?)'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-6984466528783338294</id><published>2009-11-11T09:36:00.020Z</published><updated>2010-02-12T19:41:28.332Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Sobre java (o por qué no sobre java)</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;p style="text-indent: 3em;"&gt;Pensando justificaciones iniciales sobre las razones que tiene uno al escribir sobre un determinado tema se me ocurrió que tal vez debería detenerme en explicar porque no elegí java o un tema especializado que tenga que ver con java al decidir el tema central de mi blog.&lt;/p&gt;&lt;p style="text-indent: 3em;"&gt;Y en principio habría razones de peso para hacerlo: es el lenguaje con el que aprendía a programar en serio y el que me da de comer y dentro de mis limitaciones es el lenguaje sobre el que mas conocimientos tengo. Por tanto sería el tema sobre el mas podra compartir con los lectores y ademas le tengo cariño, el mismo que se tiene a tu primer amor aunque haga tiempo que no lo sea.&lt;br /&gt;&lt;/p&gt;&lt;p style="text-indent: 3em;"&gt; Sin embargo ya no es la herramienta con la que mas a gusto estoy por mucho cariño que le tenga. Tal vez, el que sea mi herramienta de trabajo diaria y la que tengo que sufrir ha influido en ello. Por otro lado al ser un lenguaje maduro (casi diría ya que un poco decrépito) hay miles de blogs y fuentes de información y no creo que pudiera aportar nada nuevo sobre él, ni siquiera en aquellos aspectos mas especializados de la J2EE.&lt;br /&gt;&lt;/p&gt;&lt;p style="text-indent: 3em;"&gt;Dejando aparte las razones personales y mis circunstancias el haberme juntado ultimamente con malas compañias funcionales ha hecho que vea mucho mas claramente sus limitaciones y rigidices y que palidezca comparandolo con cualquiera de los lenguajes o dialectos mas modernos desde python hasta clojure pasando por groovy o scala.&lt;br /&gt;&lt;/p&gt;&lt;p style="text-indent: 3em;"&gt;Parte del cambio de mi punto de vista se ha debido a &lt;a href="http://www.paulgraham.com/"&gt;esta mala compañia&lt;/a&gt; y sus ensayos sobre la &lt;a href="http://www.paulgraham.com/hundred.html"&gt;historia y futuro de los lenguajes de programación&lt;/a&gt; y en concreto &lt;a href="http://www.paulgraham.com/javacover.html"&gt;sobre java&lt;/a&gt;. En ellas compara a java con cobol, no tecnicamente, sino funcionalmente en el sentido de su función "social". Java es el actual lenguaje de programacion estrella del mundo de los negocios y se mueve mucho dinero a su alrededor.  A medida que un lenguaje gana en popularidad es mas dificil realizar cambios sobre el y estos cada vez son mas leves (como le esta pasando a &lt;a href="http://www.vivalinux.com.ar/eventos/moratoria-para-python3"&gt;python&lt;/a&gt;). Si encima los "protectores" del lenguaje son Oracle e Ibm es totalmente explicable que java ya apenas pueda variar y adaptarse a los nuevos tiempos recogiendo los nuevos avances en el campo de los lenguajes de programación.&lt;br /&gt;&lt;/p&gt;&lt;p style="text-indent: 3em;"&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;PD: Hace unos días y ante el clamor popular &lt;/span&gt;&lt;a style="font-style: italic;" href="http://java.dzone.com/news/closures-coming-java-7"&gt;se ha anunciado oficialmente&lt;/a&gt;&lt;span style="font-style: italic;"&gt; que finalmente java 7 tendra closures, contradiciendo mis argumentos en parte, cosa&lt;/span&gt; &lt;span style="font-style: italic;"&gt;de la que me alegro muy sinceramente. El unico problema es que en mi trabajo diario todavia estoy peleandome con el 1.4 pero todo llegara...&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-6984466528783338294?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/6984466528783338294/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/11/sobre-java-o-por-que-no-sobre-java.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6984466528783338294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/6984466528783338294'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/11/sobre-java-o-por-que-no-sobre-java.html' title='Sobre java (o por qué no sobre java)'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-8722802357964141375</id><published>2009-06-03T07:50:00.023+01:00</published><updated>2010-02-12T11:34:36.661Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='closures'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='introduccion'/><title type='text'>Qué es una closure</title><content type='html'>&lt;div style="text-align: justify;"&gt;Bueno casi parecía obligada una entrada que explicara el título del blog ya que closure podria traducirse como &lt;del&gt;cierre&lt;/del&gt; clausura y con un poco (o un mucho) mas de licencia al traducir "cerradura".&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Cuando estudiaba la carrera hubo un ejercicio en java en el que me vi obligado a iterar varias veces sobre una estructura de datos para realizar operaciones sobre ellas. Entonces me vino la idea de porque no se podría pasar un método como parametro para no tener que repetir una y otra vez la estructura de iteración.&lt;br /&gt;&lt;br /&gt;En mi mente lo que queria era algo así:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    public void doForAll (Collection coll,Method m) {&lt;br /&gt;          for (item in coll) "ejecutar codigo de m &lt;br /&gt;           sobre cada elemento de la coleccion";&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Le pregunte a mi profesor y su rapida respuesta fue NO.&lt;br /&gt;Y no tenia razon claro porque en el mismo java se puede hacer algo así con clases anónimas. Usando el Commons Collection de Apache:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   CollectionUtils.doForAll (coll, new Closure () {&lt;br /&gt;              public void execute(Object arg0) {&lt;br /&gt;                    "ejecutar codigo sobre cada &lt;br /&gt;                     elemento arg0 de la coleccion"&lt;br /&gt;              }});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Este "hack" se basa en las clases anonimas, implementaciones ad hoc normalmente de una interfaz. Gracias a ellas podemos implementar codigo justo en el sitio que lo necesitamos (si solo lo vamos a necesitar en un sitio y no va a hacer falta reutilizarlo)&lt;br /&gt;&lt;br /&gt;Sin embargo aunque la interfaz se llama "closure" solo se parece y es una opción muy limitada si la comparamos con las closures reales de los lenguajes funcionales.&lt;br /&gt;&lt;br /&gt;En javascript, python, ruby, groovy y la familiar de los lisp entre otros el codigo organizado en bloques es un "objeto" de primera clase. O sea puedes asignar a una variable un bloque de codigo, pasarlo como parametro y devolverlo en una funcion y ejecutarlo en el momento y lugar necesario.&lt;br /&gt;&lt;br /&gt;En el caso de java con las clases anónimas puedes encapsular el código en una clase (con lo que se añade un elemento totalmente prescindible que hace de intermediario), crear una instancia y pasarla como parámetro y devolverla.&lt;br /&gt;&lt;br /&gt;¿Donde esta la limitación? en la capacidad de las closures (por definición) de "capturar" las variables del contexto donde son definidas. Para que las clases anónimas puedan usar las variables externas a su bloque estas deben ser marcadas finales, es decir no modificables. Sin embargo con las closures reales el código mantiene una referencia a la variable en el momento de la definición del bloque de código y esta puede ser modificada antes y despues por el codigo &lt;b&gt;y por la propia Closure&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Veamos un ejemplo en javascript (&lt;a href="http://blog.morrisjohns.com/javascript_closures_for_dummies"&gt;tomado de esta interesante página en Inglés&lt;/a&gt;):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;function say667() {&lt;br /&gt; // Local variable that ends up within closure&lt;br /&gt; var num = 666;&lt;br /&gt; var sayAlert = function() { alert(num); }&lt;br /&gt; num++;&lt;br /&gt; return sayAlert;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;var f=say667();&lt;br /&gt;f();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿Que nos alerta la función? como es previsible por el nombre de la función "madre" que la ha creado nos pone "667" (Podeis comprobarlo en la pagina)&lt;br /&gt;&lt;br /&gt;Bien todo esto de capturar las variables es muy bonito pero así de primeras no se le ve una gran utilidad. Sin embargo sí la tiene ya que en java esto es imposible de hacer:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defn make-adder [x] #(+ x %1))&lt;br /&gt;(def add5 (make-adder 5))&lt;br /&gt;(add5 8)&lt;br /&gt;; Nos pintaria 13&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Un ejemplo ya clásico de Paul Graham en su magnifica introducción a Lisp: &lt;a href="http://www.paulgraham.com/onlisp.html"&gt;On Lisp&lt;/a&gt; implementada en el dialecto de lisp &lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Para los que sienten extrañeza, temor o repelus a los parentesis (aunque son bien parecidos a las llaves) habrá que explicar que make-adder es una función que genera funciones de suma. Que add5 es una variable que apunta a una función creada con la anterior que suma 5 a un numero dado y que al ser llamada con un parámetro de 8 nos devolvería 13.&lt;br /&gt;&lt;br /&gt;...precioso verdad.&lt;br /&gt;&lt;br /&gt;Para los que todaváa no esten convencidos veamos las closures otra vez en acción:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(filter #(&gt; %1 5) '(1 2 3 4 5 6 7 8 9))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Esta funcion filtra los datos de una lista usando una funcion ("#(&gt; %1 5)") que compara cada uno de los elementos de la lista y los mete en otra solo si cumplen la condicion.&lt;br /&gt;En este caso la devolucion seria (6 7 8 9).&lt;br /&gt;Claro como el agua, breve como un parpadeo y picante como una guindilla si me permitis calificar asi un codigo.&lt;br /&gt;&lt;br /&gt;Os dejo a vuestra imaginación las posibilidades que se abren con estos cierres.&lt;br /&gt;&lt;br /&gt;PD: Expongo el ejemplo en haskell, otro de los lenguajes estrellas del paradigma declarativo funcional (mas lejano y puro todavía que clojure)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt;let makeAdder :: Int -&gt; (Int -&gt; Int);makeAdder x=(x +)&lt;br /&gt;&gt; let add5=makeAdder 5&lt;br /&gt;&gt; add5 6&lt;br /&gt;11&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-8722802357964141375?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/8722802357964141375/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/06/que-es-una-closure.html#comment-form' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/8722802357964141375'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/8722802357964141375'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/06/que-es-una-closure.html' title='Qué es una closure'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-9160898152193512323</id><published>2009-05-26T07:04:00.009+01:00</published><updated>2009-06-04T06:53:56.686+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='compatibilidad'/><category scheme='http://www.blogger.com/atom/ns#' term='ie'/><title type='text'>El lado oscuro del Javascript: JScript</title><content type='html'>&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://pressthebuttons.typepad.com/photos/uncategorized/2007/12/28/mariovwario.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px; height: 288px;" src="http://pressthebuttons.typepad.com/photos/uncategorized/2007/12/28/mariovwario.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       Bueno no todo iba a ser un camino de rosas. Al igual que Mario tiene su Wario Javascript tiene su lado oscuro nacido en los pozos y hornos de Redmond: JScript. Su principal caracteristica defectuosa es el ir a la contra. En otros aspectos eso me produciria simpatia pero programando NO.&lt;br /&gt;&lt;br /&gt;      JScript cumple la especificacion ECMAScript pero en varios huecos la implementacion es al reves que la del resto de motores (Opera,Mozilla,Chrome). Una buena manera de no quedarse atrancado en las compatibilidades es echarle un vistazo a como las diferencias pueden afectar a tu codigo en &lt;a href="http://www.quirksmode.org/"&gt;quirksmode&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-9160898152193512323?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/9160898152193512323/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/05/el-lado-oscuro-del-javascript-jscript.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/9160898152193512323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/9160898152193512323'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/05/el-lado-oscuro-del-javascript-jscript.html' title='El lado oscuro del Javascript: JScript'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-1979467169462232702</id><published>2009-05-20T06:35:00.011+01:00</published><updated>2009-05-26T07:25:42.883+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>I ♥ javascript</title><content type='html'>Fruto de mis devaneos funcionales he caido en el amor a javascript en su faceta mas funcional. La celeberrima libreria &lt;a href="http://jquery.com"&gt;jquery&lt;/a&gt; ahonda en esa faceta de javascript y tambien la reintroduccion que aparece en el &lt;a href="https://developer.mozilla.org/en/a_re-introduction_to_javascript"&gt;developer center de mozilla.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Por ejemplo con javascript puedes hacer virgueria como esta:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;function call (functionName) {&lt;br /&gt; try {&lt;br /&gt;  if (functionName) func=eval(functionName);&lt;br /&gt;  if (func &amp;&amp; func instanceof Function) &lt;br /&gt;   return func.apply (null,rest(arguments));&lt;br /&gt; } catch (e) {}&lt;br /&gt; return null;&lt;br /&gt;}&lt;br /&gt;function rest (list) {&lt;br /&gt; var result=[];&lt;br /&gt; for (var i=0;i&amp;#60;list.length;i++) &lt;br /&gt;  if (i!=0) result[length]=list[i];&lt;br /&gt; return result;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Esta funcion evalua un String pasado como primer parametro y si el resultado es una funcion retorna el valor de esa funcion pasandole el resto de parametros.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-1979467169462232702?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/1979467169462232702/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/05/i-javascript.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/1979467169462232702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/1979467169462232702'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/05/i-javascript.html' title='I ♥ javascript'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-700063804771909929</id><published>2009-04-20T19:55:00.007+01:00</published><updated>2009-10-24T14:22:38.189+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='1.0'/><title type='text'>Clojure cumple su primer cumpleaños</title><content type='html'>O sea, se ha publicado &lt;a href="http://clojure.blogspot.com/2009/05/clojure-10.html"&gt;la version 1.0&lt;/a&gt; despues de un prudente periodo sin bugs ni problemas en el nucleo del lenguaje. Como el mismo creador exponia &lt;a href="http://groups.google.com/group/clojure/browse_thread/thread/2ee2b28e9dd3516b/7c45c2d4ecd8ca2f?lnk=gst&amp;q=1.0#7c45c2d4ecd8ca2f"&gt;en el foro de la comunidad&lt;/a&gt; las razones tienen que ver mas con la divulgacion del lenguaje que otra cosa. Esperemos que la evangelizacion prosiga y pronto sea una religion dominante.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-700063804771909929?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/700063804771909929/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/04/clojure-cumple-su-primer-cumpleanos.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/700063804771909929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/700063804771909929'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/04/clojure-cumple-su-primer-cumpleanos.html' title='Clojure cumple su primer cumpleaños'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4243588728844398089.post-952444514516217917</id><published>2009-04-20T08:27:00.012+01:00</published><updated>2009-05-20T08:41:59.669+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='funcional'/><category scheme='http://www.blogger.com/atom/ns#' term='intro'/><title type='text'>Inauguracion del barco</title><content type='html'>Hello world my dear friends. Al final me he animado a iniciar las entradas de este blog, orientandolo hacia un tema sobre el que todavia no hay mucho material escrito en castellano: el lenguaje de programacion &lt;a href="http://clojure.org"&gt;Clojure &lt;/a&gt; y el renaciente interes de la comunidad de programadores por el &lt;a href="http://en.wikipedia.org/wiki/Functional_programming"&gt;paradigma funcional&lt;/a&gt;, marginado del mainstream durante mucho tiempo.&lt;br /&gt;&lt;br /&gt;Intentare reproducir en sucesivas entradas tanto los motivos de este interes como mi recien iniciado aprendizaje en este hermoso lenguaje.&lt;br /&gt;&lt;br /&gt;Y como una imagen vale mas que mil palabras:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_86RNxT2sO_o/Sew5AWjeqsI/AAAAAAAAACw/lp_BZBCCt9E/s1600-h/fringe.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 154px;" src="http://2.bp.blogspot.com/_86RNxT2sO_o/Sew5AWjeqsI/AAAAAAAAACw/lp_BZBCCt9E/s400/fringe.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5326695137489627842" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4243588728844398089-952444514516217917?l=javierneirasanchez.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javierneirasanchez.blogspot.com/feeds/952444514516217917/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/04/inauguracion-del-barco.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/952444514516217917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4243588728844398089/posts/default/952444514516217917'/><link rel='alternate' type='text/html' href='http://javierneirasanchez.blogspot.com/2009/04/inauguracion-del-barco.html' title='Inauguracion del barco'/><author><name>Javier</name><uri>http://www.blogger.com/profile/03081252416288495482</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_86RNxT2sO_o/Sew5AWjeqsI/AAAAAAAAACw/lp_BZBCCt9E/s72-c/fringe.png' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
