¿Qué perdería Clojure si dejara de paréntesis como Dylan, Julia y Seph?
lisp julia-lang (9)
Tres lenguajes homoicónicos lispy, Dylan , Julia y Seph, todos se alejaron del paréntesis inicial, por lo que una llamada de función hipotética en Common Lisp se vería así:
(print hello world)
Se vería como la siguiente llamada de función hipotética
print(hello world)
en los tres idiomas mencionados anteriormente.
Si Clojure siguiera este camino, ¿qué tendría que sacrificar para llegar allí?
Razonamiento: además de las asombrosas estructuras de datos funcionales de Clojure, la sintaxis mejorada para mapas y seqs, el soporte de idiomas para la concurrencia, la plataforma JVM, las herramientas y la increíble comunidad, lo distintivo de que es ''un LISP'' es paréntesis principal que proporciona homoiconicidad que proporciona macros que proporcionan abstracción de sintaxis.
Pero si no necesitas paréntesis iniciales, ¿por qué tenerlos? Los únicos argumentos en los que puedo pensar para mantenerlos son
(1) reutilización de soporte de herramientas en emacs
(2) incitando a las personas a ''pensar en LISP'' y no intentar y tratarlo como otro lenguaje de procedimiento)
Escribir macros sería mucho más difícil porque la estructura ya no sería simple, necesitaría otra forma de codificar donde las expresiones comienzan y dejan de usar algún símbolo sintáctico para marcar el inicio y el final de las expresiones. Puede escribir código que genere expresiones, tal vez podría resuelve este problema agregando algo así como a (
para marcar el comienzo de la expresión ...
En un ángulo completamente diferente, vale la pena ver este video sobre la diferencia entre familiar y fácil, haciendo que la sintaxis de lisps sea más familiar, no facilitará el aprendizaje de las personas y puede hacer que sea engañoso si se parece mucho a algo que no es.
incluso si no está de acuerdo, ese video vale la pena.
Simplemente mover los paréntesis un átomo para llamadas de función no sería suficiente para satisfacer a nadie; las personas se quejarán de la falta de operadores de infijo, bloques de inicio / fin, etc. Además, probablemente tendrías que introducir comas / delimitadores en todo tipo de lugares.
Darles eso y las macros será mucho más difícil solo para escribir correctamente (y probablemente sea aún más difícil escribir macros que se vean y funcionen bien con toda la nueva sintaxis que hayas introducido para entonces). Y las macros no son algo que sea una buena característica que puede ignorar o hacer mucho más molesto; el lenguaje completo (como cualquier otro Lisp) se construye justo encima de ellos. La mayoría de las cosas "visibles para el usuario" que están en clojure.core, incluidas let, def, defn, etc. son macros.
Were Clojure to go down this path - what would it have to sacrifice to get there?
El sacrificio sería el sentimiento / mental-modal de escribir código al crear la Lista de la Lista de la Lista ... o más técnicamente "escribir la AST directamente".
NOTA: También hay otras cosas que serán escarificadas como se menciona en otras respuestas.
Solía codificar C / C # / Java / Pascal, así que enfatizo con la sensación de que el código Lisp es un poco extraño. Sin embargo, esa sensación solo dura unas pocas semanas: después de un período de tiempo bastante corto, el estilo Lisp se sentirá muy natural y comenzarás a reprender a otros idiomas por su sintaxis "irregular" :-)
Hay una muy buena razón para la sintaxis de Lisp. Liderar paréntesis hace que el código sea lógicamente más simple de analizar y leer, al recopilar una función y las expresiones que componen sus argumentos en una sola forma.
Y cuando manipulas código / uso de macros, son estas formas las que importan: estos son los componentes básicos de todo tu código. Por lo tanto, tiene sentido poner los paréntesis en un lugar que delimite exactamente estos formularios, en lugar de dejar arbitrariamente el primer elemento fuera del formulario.
La filosofía del "código es datos" es lo que hace posible la metaprogramación confiable. Compare con Perl / Ruby, que tienen una sintaxis compleja, sus enfoques para la metaprogramación solo son confiables en circunstancias muy confinadas. La metaprogramación de Lisp es tan perfectamente confiable que el núcleo del lenguaje depende de ello. La razón de esto es la sintaxis uniforme compartida por el código y los datos (la propiedad de la homoiconicidad). Las expresiones S son la forma en que se realiza esta uniformidad.
Dicho esto, hay circunstancias en Clojure donde el paréntesis implícito es posible:
Por ejemplo, las siguientes tres expresiones son equivalentes:
- (primero (resto (resto [1 2 3 4 5 6 7 8 9])))
- (-> [1 2 3 4 5 6 7 8 9] (descanso) (descanso) (primero))
- (-> [1 2 3 4 5 6 7 8 9] descanso en primer lugar)
Observe que en el tercero, la macro -> puede en este contexto inferir paréntesis y, por lo tanto, dejarlos fuera. Hay muchos escenarios de casos especiales como este. En general, el diseño de Clojure se equivoca en el lado de menos paréntesis. Véase, por ejemplo, la controvertida decisión de dejar de paréntesis en cond. Clojure tiene principios y es consistente con esta elección.
no necesitarías sacrificar nada. hay un enfoque muy cuidadosamente pensado por el rodador de David que es completamente transparente y compatible con versiones anteriores, con soporte completo para macros, etc.
(Crédito a la respuesta de andrew cooke, que proporcionó el enlace al "Proyecto de expresiones S de legible legible" de Wheeler y Gloria)
El enlace anterior es un proyecto destinado a proporcionar una sintaxis legible para todos los idiomas basada en s-expressions, incluidos Scheme y Clojure. La conclusión es que se puede hacer: hay una manera de tener Lisp legible sin los paréntesis .
Básicamente, lo que hace el proyecto de David Wheeler es agregar azúcar sintáctico a los lenguajes tipo Lisp para proporcionar una sintaxis más moderna, de una manera que no rompa el soporte de Lisp para los lenguajes específicos del dominio. Las mejoras son opcionales y compatibles con versiones anteriores, por lo que puede incluir tanto o tan poco de lo que desee y mezclarlas con el código existente.
Este proyecto define tres nuevos tipos de expresiones:
- Curly-infix-expressions. (+ 1 2 3) se convierte en {1 + 2 + 3} en cada lugar en el que desee usar operadores de infijo de cualquier aridad. (Hay un caso especial que debe manejarse con cuidado si la expresión en línea usa varios operadores, como {1 + 2 * 3} - aunque {1 + {2 * 3}} funciona como se esperaba).
- Expresiones neotericas (fxy) se convierte en f (xy) (requiere que no se coloque espacio entre el nombre de la función y sus parámetros)
- Dulces expresiones. Los padres que abren y cierran pueden ser reemplazados con sangría semántica (opcional) similar a pitón . Las expresiones dulces se pueden mezclar libremente con las expresiones s tradicionales de paréntesis.
El resultado es un código compatible con Lisp pero mucho más legible. Un ejemplo de cómo el nuevo azúcar sintáctico mejora la legibilidad:
(define (gcd_ a b)
(let (r (% b a))
(if (= r 0) a (gcd_ r a))))
(define-macro (my-gcd)
(apply gcd_ (args) 2))
se convierte en:
define gcd_(a b)
let r {b % a}
if {r = 0} a gcd_(r a)
define-macro my-gcd()
apply gcd_ (args) 2
Tenga en cuenta cómo la sintaxis es compatible con las macros, que era un problema con los proyectos anteriores que tenían la intención de mejorar la sintaxis de Lisp (como lo describen Wheeler y Gloria). Debido a que es solo azúcar, la forma final de cada nueva expresión es una expresión s, transformada por el lector de lenguaje antes de que se procesen las macros, por lo que las macros no necesitan ningún tratamiento especial. Por lo tanto, el proyecto "Lisp legible" preserva la homoiconicidad, la propiedad que permite a Lisp representar código como datos dentro del lenguaje, que es lo que le permite ser un poderoso entorno de meta-programación.
Tendrás Mathematica. Mathematica acepta las llamadas a funciones como f[x, y, z]
, pero cuando lo investigas más a fondo, encuentras que f[x, y, z]
es en realidad azúcar sintáctica para una lista en la que la Head
(elemento 0) es f
y el Rest
(elementos 1 a N) es {x, y, z}
. Puede construir llamadas a funciones a partir de listas que se parecen mucho a las expresiones S y puede descomponer funciones no evaluadas en listas ( Hold
impide la evaluación, al igual que la quote
en Lisp).
Puede haber diferencias semánticas entre Mathematica y Lisp / Scheme / Clojure, pero la sintaxis de Mathematica es una demostración de que puede mover el paréntesis izquierdo en un átomo y aún así interpretarlo con sensatez, crear código con macros, etc.
La sintaxis es bastante fácil de convertir con un preprocesador (mucho más fácil que la semántica). Probablemente puedas obtener la sintaxis que quieras a través de algunas subclases inteligentes de LispReader de Clojure . Incluso hay un proyecto que busca resolver paréntesis desagradables de Clojure reemplazándolos con corchetes. (Me sorprende que esto se considere un gran problema).
Curiosamente, hay una sintaxis alternativa de Racket :
@foo{blah blah blah}
lee como
(foo "blah blah blah")