Clojure
|
Clojure (pronunciado [cloushur]), es un dialecto del lenguaje de programación Lisp. Es un lenguaje de propósito general que ofrece un estilo de programación interactiva y que incentiva una forma de programar funcional, simplificando así la programación concurrente. Clojure puede ejecutarse tanto en la máquina virtual Java (JVM) como en la máquina virtual de la plataforma .Net, e incluso se puede compilar hacia Javascript.
Sumario
Principios
Rich Hickey creó el lenguaje Clojure en el año 2007. Describe el desarrollo de este lenguaje como la búsqueda de un lenguaje que no pudo encontrar: un lisp funcional por defecto, integrado sobre un entorno robusto en lugar de ser su propia plataforma, y con la programación concurrente en mente.
Asimismo, en principio se rechaza la orientación a objetos, ofreciendo un enfoque en el que los programas se expresan como la aplicación de funciones sobre datos, más que como la interacción entre entidades mutables que mezclan representación de datos, y comportamiento. Por otra parte, características tales como instanciabilidad, Polimorfismo e interfaces son efectivamente parte del lenguaje.
Sintaxis
La sintaxis de Clojure se basa en S-expresiones (estructuras de datos basadas en listas) que son parseadas y posteriormente compiladas. Soporta sintaxis literal para listas (), vectores [], mapas {} y conjuntos #{}. Es un Lisp-1 soporta usar funciones en variables como una función normal pero no es compatible en código con otros dialectos de Lisp.
Ejemplos de código
- Función elevar al cuadrado
(defn square [x] (* x x)).
- Factorial recursivo
(defn fact [n] (if (> n 1). (* n (fact (dec n))). 1)).
- Factorial con loop (Falso recursivo).
(defn fact [n] (loop [current 2 accum 1] (if (< current n). (recur (inc current) (* accum current)). (* accum current)))).
- Factorial con reduce
(defn fact [n] (reduce * (range 2 n))).
- Interoperabilidad con Java
(javax.swing.JOptionPane/showMessageDialog nil "Hello World").
- Un generador de números únicos y consecutivos que soporta llamadas concurrentes
(let [i (atom 0)] (defn generar-id-unica "Devuelve un identificador numérico distinto para cada llamada." [] (swap! i inc))).
Características de Clojure
- Simplicidad: En Clojure hay un conjunto de componentes básicos (tipos de datos, estructuras de control, funciones ofrecidas por el lenguaje) apropiado para un lenguaje que ofrece soporte al paradigma de programación funcional. Al ser Clojure un dialecto de Lisp es un poco más simple que este y ofrece una sintaxis un poco más concisa.
- Ortogonalidad: Clojure es un lenguaje que posee una alta ortogonalidad debido a que con el conjunto de constructores primitivos, se pueden combinar de una gran cantidad de formas y así construir estructuras de control y de datos más complejas. La ortogonalidad manejada por este lenguaje afecta positivamente a la legibilidad por su grado de regularidad.
- Tipos de datos: En el paradigma funcional los programas manipulan los datos. Básicamente, Clojure es compatible con números, strings, caracteres, palabras claves, símbolos y colecciones. Además de estas colecciones, el lenguaje también ofrece la posibilidad de importar colecciones y clases desde Java.
- Soporte para la abstracción: Clojure mediante las colecciones permite crear nuevos tipos de datos con los cuales se puede modelar de una mejor manera la realidad que se intenta reflejar en el código.
- Expresividad: La expresividad del lenguaje es sumamente alta debido a que hay operadores muy poderosos que permiten que permiten lograr mucho cálculo con pocas líneas de código. Esto se le atribuye a la naturalidad con que se expresa este paradigma funcional.
- Chequeo de tipos: Durante la fase en la que el Reader lee el código fuente para traducirlo a las estructuras de datos, se hace un chequeo de tipos para que los tipos de datos coincidan con los esperados por las funciones y expresiones a evaluar. Las expresiones no válidas generan un “error de lectura”, con lo que se muestra un mensaje de error apropiado y se aborta el programa. En la segunda fase se evalúan las expresiones y sus valores de retorno. El código es compilado a bytecode, y se ejecuta sobre la JVM (máquina virtual Java). Este punto afecta positivamente la confiabilidad del lenguaje, ya que el chequeo de tipos que realiza el lenguaje es riguroso.
- Manejo de excepciones: En Clojure el manejo de excepciones es muy similar a Java, pero está mucho más simplificado. Provee mecanismos que hacen que no sea tan necesario capturar explícitamente las excepciones que se generan en tiempo de ejecución, a menos que sea sumamente necesario. No se necesita capturar las excepciones explícitamente en Clojure Se pueden utilizar las macros with-open que ofrecen una funcionalidad similar al finally en Java, que garantizan que después de utilizar un recurso, por más que se genere una excepción, el recurso sea borrado o cerrado (internamente, la macro genera una estructura try y la atiende de ser necesario) Esta característica del lenguaje afecta positivamente su Confiabilidad, ya que el programador no tiene que estar tan pendiente de atender explícitamente al manejo de excepciones y a los errores que pueden ocurrir en la ejecución.
- Concurrencia: Como técnicas de Clojure para el soporte de concurrencia se puede incluir a los agentes, que realizan las acciones de manejo de estado y manejo de ejecución. Como las variables son tratadas como trataría cualquier lenguaje a una constante, es decir, permanecen inmutables, es ahí donde entra en acción el manejo de estados ya que poco podríamos modelar si no podríamos modificar las variables. En el manejo de estados lo que realiza el agente es, como todos los elementos internamente los trata como secuencias, si necesitamos eliminar o insertar datos en una variable, crea una nueva variable y los enlaza o los borra temporalmente. En el manejo de ejecución, los agentes son los que dan ejecución, pausa o muerte a los subprogramas, y su propósito es, obviamente, la concurrencia pero con un aprovechamiento eficiente de los procesadores por lo cual requiere de la JVM para no solo saber cuántos procesadores hay sino los costos de los accesos remotos a los recursos.
Ventajas de Clojure sobre otros lenguajes
- El código en clojure es de 1 a 10 órdenes de magnitud más pequeño que en Java, esto es, de 10 a 100 veces menos código.
- Recursión BIEN implementada.
- Tiene una REPL (read eval print loop), desarrollo dinámico con una consola de evaluación.
- Las funciones son objetos de primera clase.
- Listas perezosas (se puede tener programados TODOS los números naturales sin ningún problema de memoria).
- Amplio conjunto de Estructuras de datos, vectores, mapas, listas, por solo mencionar algunos.
- Produce código de la JVM.
- Se puede utilizar Clases de Java para trabajar con Clojure.
- Como característica diferente al resto de Lisps implementa multihilos, permitiendo polimorfismo estilo POO.