Project Euler: Problema 4 con clojure

Sigo resolviendo problemas del proyecto euler para practicar con Clojure y de paso ir comentando cosas sobre este particular lenguaje.

Hoy toca el problema 4:

Un número capicúa es aquel que se lee igual de izquierda a derecha que de derecha a izquierda. El mayor número capicúa que se puede formar como producto de números de dos dígitos es 9009 = 91 x 99.

Encuentra el mayor número capicúa formado como producto de dos números de 3 dígitos.

Se trata de un problema bastante sencillo que podemos resolver con el siguiente código:

(apply max 
  (filter (comp #(= (seq %) (reverse %)) 
                str) 
          (for [x (range 100 999) 
                y (range 100 999)] 
            (* x y))))

En este fragmento tan pequeño de código vemos bastantes cosas interesantes de Clojure:

  • Podemos usar for para generar secuencias perezosas a partir de los bindings que queramos. Es la misma idea que los list comprehensions de python. En este caso partimos de las variables x e y, que toman todos los valores posibles entre 100 y 999, y calculamos su producto.
  • La función comp nos permite generar una nueva función mediante la composición (en sentido matemático) de otras funciones. Es decir, (comp f g) devuelve una función que aplica primero g y luego f.
  • Para invertir una cadena de texto, aunque se puede usar clojure.string/reverse, estamos usando clojure.core/reverse, que funciona con cualquier tipo de colección, pero tiene el inconveniente de devolver una secuencia (en lugar de una cadena de texto). Por eso para poder comparar tenemos que convertir la cadena de texto original en una secuencia usando la función seq.

Nuevamente podemos comprobar la forma en que Clojure podemos realizar operaciones relativamente complejas partiendo de funciones simples y usándolas como argumentos de funciones de orden superior (funciones que reciben otras funciones como argumentos).

Esta es una forma bastante habitual de trabajar con Clojure (al menos en el código que he visto hasta ahora) y permite escribir código muy terso, aunque a veces puede resultar poco legible, especialmente si no estás acostumbrado a ver tanto paréntesis junto.

3 comentarios en “Project Euler: Problema 4 con clojure

  1. Hola , estoy siguiendo tus tutoriales sobre clojure y la verdad es que estoy bastante perdido.
    Entiendo que en este código en la parte del for el resultado de la multiplicación de ‘x’ e ‘y’ se pasa a la función str después a reverse seguido a seq , pero no entiendo el signo = .
    La verdad es que me pierdo a la hora de leer el código escrito en clojure es realmente obtuso.

  2. Hola Sergio,

    La sintaxis de clojure puede resultar confusa al principio, y el estilo funcional, si no estás acostumbrado, tampoco ayuda, así que no te preocupes si te pierdes; esto requiere un poco de práctica.

    La idea de este código es generar usando el for todos los productos de números de tres dígitos. Eso te genera una secuencia perezosa sobre la que se aplica un filtro para quedarnos sólo con los que son capicúas y, luego tomar el máximo de ellos.

    El filtro, que es la parte que te resulta más confusa, utiliza una función que lo que hace es, más o menos:

    1) convierte el número a string usando la función str
    2) comprueba si el string es un palíndromo, viendo si es igual visto en una dirección (seq %) que en otra (reverse %). Esto es lo que se escribe como: #(= (seq %) (reverse %)).

    Como ves, la función que queremos usar para filtrar tiene dos pasos, y lo que hacemos es crear una función usando comp formada por la aplicación de esos dos pasos.

    De todas formas, el código que tengo en estos ejemplos seguramente no sea el mejor (a fin de cuentas, es el primer código que escribí mientras aprendía clojure).

    Una buena página para practicar clojure es http://4clojure.org donde puedes resolver problemas sencillos y luego comparar tu solución con la de otros.

    Un saludo,

    Juanma.

  3. Vale ahora lo entiendo mejor , de todas maneras la documentación de clojure es tan oscura como su sintaxis….
    Muy buenos los artículos , espero que sigas con clojure , se esta convirtiendo en un reto esto de la programación funcional para mi :)
    Saludos.

Comentarios cerrados.