¿Lisp todavía tiene alguna característica especial que NO haya sido adoptada por otros lenguajes de programación?

35

¿Lisp todavía tiene alguna característica especial que NO haya sido adoptada por otros lenguajes de programación?

Por Lisp, me refiero a todos los lenguajes de programación de Lisp en su conjunto. Me han dicho lo increíble que es Lisp y sé que muchos idiomas han sido inspirados por Lisp. ¿Pero Lisp todavía tiene alguna característica de diseño exclusiva que simplemente no se puede hacer en ningún otro idioma?

La razón por la que hice la pregunta es que recientemente, como programador aficionado, comencé a aprender Clojure solo por diversión, y el resultado es que encontré muchas publicaciones y comentarios relacionados con Lisp, diciendo una sola cosa: "Lisp es único ", pero otros lenguajes de programación modernos ya han adoptado y robado muchas ideas de Lisp, como los condicionales, la recursión y la función como ciudadano de primera clase. E incluso la metaprogramación puede ser realizada por muchos idiomas.

¿Me perdí algo y "Lisp sigue siendo diferente"?

O tengo suerte porque otros idiomas modernos han robado todas las partes buenas de Lisp, por lo que no es necesario profundizar en el mundo de Lisp entre paréntesis , y "Lisp era diferente".

iceX
fuente
3
Compartir su investigación ayuda a todos. Cuéntanos qué has probado y por qué no satisfizo tus necesidades. Esto demuestra que te has tomado el tiempo para tratar de ayudarte a ti mismo, nos salva de reiterar respuestas obvias y, sobre todo, te ayuda a obtener una respuesta más específica y relevante. También vea Cómo preguntar
mosquito
3
@gnat Thx para consejos, y he actualizado mi pregunta :)
iceX
10
Un problema es que, una vez que un lenguaje tiene un cierto subconjunto de características de Lisp (por ejemplo, expresiones S y macros), las personas afirman que es un Lisp. Lo que, por supuesto, tiene la consecuencia de que (según estas personas) ningún lenguaje que no sea Lisp puede tener estas características.
99
Supongo que no hay otro idioma donde los corchetes son la única forma de agrupación para todo :-)
Doc Brown
Lisp como familia puede no ser terriblemente único, pero muchos dialectos lisp (Racket, CL, Scheme, Clojure) aún ofrecen muchas características útiles / únicas.
Daniel Gratzer

Respuestas:

28

Una referencia canónica para este tipo de preguntas es What Grays Lisp Different, de Paul Graham . Las dos características clave restantes de Lisp que no están ampliamente disponibles, según este artículo en el momento de su redacción, son:

8. Una notación para el código usando árboles de símbolos.

9. Todo el idioma siempre disponible. No existe una distinción real entre tiempo de lectura, tiempo de compilación y tiempo de ejecución. Puede compilar o ejecutar código mientras lee, lee o ejecuta código mientras compila, y lee o compila código en tiempo de ejecución.

El comentario aborda cada punto y nombra los idiomas populares donde está disponible esa función.

8, que (con 9) es lo que hace posible las macros de Lisp, hasta ahora es único para Lisp, tal vez porque (a) requiere esos parens, o algo igual de malo, y (b) si agrega ese incremento final de poder , ya no puede pretender haber inventado un nuevo lenguaje, sino solo haber diseñado un nuevo dialecto de Lisp; -)

Tenga en cuenta que este artículo fue revisado por última vez en 2002, y en los últimos 11 años ha habido una gran variedad de nuevos idiomas, algunos de los cuales pueden incorporar todas estas características de Lisp en su diseño.

Greg Hewgill
fuente
2
Esas características no son exclusivas de Lisp (y variantes derivadas directamente), y no lo han sido durante mucho tiempo.
Donal Fellows
21
@iceX: La diferencia entre JavaScript e idiomas como Lisp, Smalltalk, Self, Newspeak, APL, Factor, Forth, etc. es que en JavaScript, los programas están "muertos". Son archivos de texto. Elimina el programa en ejecución, edita el archivo de texto y luego inicia una copia completamente nueva del programa. En esos otros (llamados entornos "animados"), nunca detiene el programa en ejecución, el programa en sí mismo es un conjunto de objetos en la memoria que manipula de la misma manera que manipula cualquier otro objeto, mientras se está ejecutando . (Nota: esto no es cierto para Clojure, pero la mayoría de los Lisps más antiguos lo hacen de esta manera.)
Jörg W Mittag
2
@ JörgWMittag Wow ... Entonces, los lenguajes de programación como Clojure, Clojurescript, lispyscript, de hecho, no son "lisp reales" porque no pueden cambiar su código de la misma manera que Lisp de la vieja escuela, como lo hace Common Lisp. Pero ... si no pueden cambiarlo ... ¿por qué molestarse en usar la expresión S, que pensé que era con el propósito de manipular el código ... (sintiendo que acabo de caer en una profunda y oscura madriguera de conejo)
iceX
44
@iceX: Muchos idiomas tienen evalo similares, y muchos pueden hacer metaprogramación, por ejemplo, Haskell's Template Haskell. Lo (posiblemente) único de Lisp es que la representación de datos, código y metacódigo es la misma, no solo en sintaxis, sino que realmente es lo mismo.
tdammers
2
@iceX Eval es solo una parte, pero no toda. En Lisp puede ejecutar código en tiempo de compilación. Puede ejecutar código en tiempo de lectura. Sí, clojure es compatible con todo el dinamismo de Lisp, tiene macros, macros de lectura y evaluación, así como la capacidad de adjuntar un REPL a un programa en ejecución para modificarlo sobre la marcha.
stonemetal
15

La pregunta es difícil de responder, ya que alguien tendría que saber todos los idiomas para saber que ningún otro tiene una característica particular disponible en Lisp, por lo que lo siguiente se basa en los idiomas con los que tengo experiencia.

Fuera de mi cabeza, las condiciones son algo que no he visto en ningún otro idioma. Piense en 'excepciones', pero donde la pila de llamadas no se desenrolla y donde la persona que llama puede enviar un valor de recuperación al sitio de excepción, pero sin perturbar la pila de llamadas entre el controlador y la fuente de la excepción. Para ser justos, esto es realmente solo una aplicación especial de continuaciones, por lo que Ruby y Scheme (al menos) pueden hacer esto.

El sistema macro de Lisp se beneficia de la regularidad / homoiconicidad, pero Scala planea incorporarlos como una característica estable en 2.12 y Template Haskell afirma características similares. Yo diría que serán más sintácticamente complejos que con Lisp, pero la generación de código en tiempo de compilación está ahí independientemente.

Ahora que lo pienso, sin embargo, la construcción directa de formularios es solo un tipo de macro disponible en Lisp: no he visto un equivalente de macros compiladoras o lectoras en ningún otro lugar.

La capacidad de algunos dialectos (por ejemplo, SBCL ) para guardar una imagen de proceso completa y reanudable es genial, pero de nuevo no es única: Smalltalk ha estado haciendo eso durante décadas.

Muchos otros lenguajes permiten la asignación de la desestructuración cuando se devuelven las matrices, pero el enfoque # 'valores y #' de valores múltiples enlazados / let-valores todavía parece ser específico para Common Lisp and Scheme (que todavía puede hacer una desestructuración 'regular' también ) El 'wantarray' de Perl permite que una función determine si se llama en un contexto escalar, de lista o vacío para que pueda ajustar su valor de retorno de una manera similar (-ish), pero no he visto valores de retorno múltiples 'verdaderos' fuera del esquema / CL.

En términos de características del lenguaje, probablemente no hay mucho que Lisp pueda hacer que otros idiomas no puedan hacer (la integridad de Turing es lo que es). Lo que es , sin embargo, es un lenguaje donde el código se expresa en términos de sus propias estructuras de datos, por lo que la idea grande ™ -que código está datos en algo que es relativamente fácil de trabajar.

Danny Woods
fuente
3
Las macros Scala son mucho menos potentes que las macros Lisp, así como las macros TH, las macros higiénicas Scheme, etc. Se puede encontrar un sistema igualmente poderoso en MetaLua y Converge.
SK-logic
4

Después de tantas décadas, no creo que haya nada exclusivo para Lisp. Pero incluso hoy, hay muchas cosas interesantes que son difíciles de encontrar fuera de Lisps. Algunas cosas que me vienen a la mente:

  • Un sistema de objetos de alta calidad con meta-protocolos sofisticados (es decir, CLOS) no es remotamente popular.
  • de vez en cuando aparecen múltiples métodos, pero la mayoría de la gente nunca escuchó sobre ellos.
  • Como otros han señalado, el sistema de condiciones es bastante sofisticado en comparación con los mecanismos de manejo de excepciones populares.
  • Una representación compacta de la semántica del lenguaje (eval), un enfoque fortalecedor para definir el lenguaje de uno y ponerlo a disposición para adaptaciones directas y profundas (ver SICP ): las funciones "eval" de los lenguajes populares actuales simplemente no comparten las mismas propiedades.

Finalmente, hay mucho más que aprender de Lisp que no se trata del lenguaje en sí, sino que se convirtió en parte de la historia de Lisp y se perdió en el tiempo. Por ejemplo, Interlisp, Symbolics Genera, etc ... si nunca pones las manos en Genera, mira este hilo de comp.lang.lisp donde Kent Pitman describe cómo "Emacs es solo una pálida sombra de los Zmacs de Genera", todo lo cual fue habilitado por teniendo un poderoso sistema Lisp del que Zmacs era parte, que se ejecutaba en una máquina Lisp.

Thiago Silva
fuente
Nunca he visto una buena explicación de los métodos múltiples que los distinguen de los métodos sobrecargados , una característica estándar en casi todos los lenguajes modernos imperativos, excepto por el hecho de que el despacho multimétodo se resuelve dinámicamente en tiempo de ejecución y, por lo tanto, es mucho más lento que el uso de métodos sobrecargados, que se resuelven en tiempo de compilación.
Mason Wheeler
Tienen distinciones importantes. Si tiene problemas para encontrar recursos sobre eso, siempre puede crear una nueva pregunta aquí ...
Thiago Silva
Julia tiene métodos múltiples, y el polimorfismo paramétrico de Haskell es algo así como métodos múltiples. Hay formas de simular métodos múltiples en muchos idiomas. El sistema de condición es algo que realmente quiero especialmente (editar y continuar, aunque lo he visto para depuradores de C #).
aoeu256
4

No es necesariamente una característica única determinada . Es todo el aspecto, y cómo ciertos conjuntos de características funcionan juntas.

JavaScript o Java tienen muchas características de Lisp (máquina virtual, compilador / evaluador, recolección de basura, etc.). Pero JavaScript, por ejemplo, carece de la parte de programación simbólica, carece de capacidades matemáticas (internamente solo tiene flotantes), carece del manejo de errores, etc.

Muchos sistemas Common Lisp están optimizados para una forma de desarrollo en la que uno extiende el nuevo software de forma incremental, al extender el lenguaje Lisp en varias dimensiones utilizando diversas técnicas de metaprogramación, sin reiniciar el software durante mucho tiempo. Por lo tanto, debe ser flexible y extensible, pero al mismo tiempo debe ser robusto. Cambiar el idioma (las macros son básicamente una forma para que el usuario extienda el compilador) sin bloquear el programa.

Ahora, algo como JavaScript también se usa para extender un programa, generalmente un navegador web. Pero la mayoría de las veces no se hace mucha meta-programación en JavaScript, además de algún hacker de OOP .

Ejemplo:

Uno puede implementar un software matemático avanzado general para el dominio del álgebra computacional en su mayoría de dos maneras: escribir el motor en C con un lenguaje especializado en la parte superior (como Mathematica ) o en algún dialecto Lisp más avanzado. Macsyma / Maxima en Common Lisp, Reducir en Standard Lisp, Axiom en Common Lisp.

(También hay uno o más escritos en Python).

No hay muchos sistemas que ofrezcan el conjunto de características de algo como Axiom , que se ejecuta sobre Common Lisp.

Lo que hizo a Lisp atractivo para este tipo de aplicaciones es una combinación de características: matemáticas básicas avanzadas (bignums, proporciones, ...), computación simbólica, compilador interactivo, etc. Es muy posible obtener estas cosas al implementarlas en un nivel bajo. Nivel de lenguaje. De esa manera, uno habrá implementado el 50% o más de un sistema Lisp típico.

Rainer Joswig
fuente
2

No hasta donde yo sé. Forth es fácilmente tan dinámico como Lisp, quizás más porque el código dinámico en Forth parece un código Forth normal, mientras que las macros Lisp tienden a usar características diferentes que el código Lisp normal (en Clojure, al menos, nunca he usado comillas de sintaxis fuera de una macro) y Como resultado, se ven muy diferentes del código normal de Lisp. Como ejemplo de cuán dinámico es Forth, aquí hay una manera de implementar comentarios en Forth :

: (   41 word drop ; immediate
( That was the definition for the comment word. )
( Now we can add comments to what we are doing! )
metal de piedra
fuente
1
Tan divertido como parece ser Forth, siempre lo encontré irremediablemente opaco e incómodo, tal vez porque está basado en la pila y todo está invertido.
Robert Harvey
2
Por curiosidad, ¿qué quieres decir con "segregado de la parte principal del idioma"? Las macros en Lisp tienen acceso completo a todas las funciones definidas en el punto en que se define la macro, cualquiera de las cuales se puede utilizar para construir el formulario al que se expande la macro. Esto podría involucrar información recuperada de una base de datos y / o servidor. Su ejemplo de comentario, podría definirse como: (comentario defmacro (& resto del cuerpo)), ¿no?
Danny Woods, el
1
@DannyWoods Quiero decir que las macros no se parecen al código normal. Al menos en clojure, puede distinguir el código macro del código regular porque usa mucho comillas de sintaxis, empalmes entre comillas, etc., lo cual es inusual en el código regular. Ese ejemplo de código que le di parece un código normal hasta que vea el inmediato. Releyendo mi respuesta, está mal expresada.
stonemetal
1
@stonemetal No se preocupe, pero vale la pena señalar que no hay nada específico de macro sobre la cita de sintaxis, ya sea en Common Lisp o Clojure. A veces es conveniente tener expresiones de backtick en definiciones de funciones regulares, y los cuerpos de macro se pueden construir manualmente con listas simples (¡aunque solo tiene que hacer esto una o dos veces para decidir que la cita de sintaxis es algo bueno!)
Danny Woods,
1
Para ser justos, lo mismo se puede hacer en Lisp, al registrar una macro de lector personalizada.
fjarri
2

Lisp tiene muchos dialectos, y cada uno de ellos tiene su propio conjunto de características. Mi característica favorita que es poco probable que sea adoptada por otro idioma es el "spaghetti stack" de Interlisp .

La pila de espagueti es como un cierre, pero con esteroides. Guarda no solo la función actual, sino todo el contexto hasta la parte superior de la pila. Algo así como una co-rutina , excepto que podría crearlos arbitrariamente, lo que da como resultado una jerarquía de contextos de pila.

ddyer
fuente
No lo sabía, lo comprobaré, gracias por tu respuesta :)
iceX
77
¿Es esto lo mismo que las continuaciones de Scheme?
Nicola Musatti
1
@NicolaMusatti, una "pila de espaguetis" es una estrategia de implementación común para las continuaciones tipo Esquema (que se puede invocar después de que la función que las creó ha regresado).
Alex D