1 puntos por GN⁺ 3 시간 전 | 1 comentarios | Compartir por WhatsApp
  • La esencia de Lisp no es la sintaxis con paréntesis, sino la forma de pensar de extender el lenguaje para ajustarlo al problema; su verdadero valor aparece al dominar el REPL, los paquetes, los símbolos, las condiciones y los reinicios
  • Gracias a la homoiconicidad, donde tanto el código como los datos se representan como listas, los macros pueden tratar el código como datos antes de evaluarlo y crear nuevas estructuras de control y abstracciones sintácticas
  • Incluso un while que no existe en Common Lisp puede agregarse con defmacro, pero si se intenta imitar con una función, los argumentos se evalúan de inmediato y body deja de ser código para convertirse en un valor
  • El desarrollo en Lisp se parece más al desarrollo guiado por REPL, donde se sigue evaluando código dentro del proceso en ejecución, redefiniendo funciones, macros y variables sin detener el programa
  • Cuando se combinan la extensibilidad del lenguaje y un sistema vivo, es posible crear software extensible que expone DSL internos a los usuarios; AutoLISP y Emacs son casos representativos

Una sensibilidad de programación distinta que Lisp exige

  • Quienes se acercan por primera vez a Lisp suelen sentirse extrañados por su sintaxis llena de paréntesis, su indentación particular y la forma en que format usa la salida estándar como primer argumento
  • Para aprender Lisp no basta con leer código: también hay que manejar paquetes y símbolos, crear proyectos, importar librerías, usar el REPL y comprender condiciones y reinicios
  • El cambio más grande aparece en la manera de construir algoritmos
    • Lisp permite hacer cosas que en otros lenguajes son difíciles, y eso también cambia la forma de los algoritmos
    • Primero se hace crecer el lenguaje para ajustarlo al problema, y luego se escribe el programa en ese lenguaje ampliado
  • El paradigma Blub explica por qué a quienes solo han usado lenguajes menos potentes les cuesta percibir las fortalezas de Lisp

Un lenguaje extensible

  • Lisp puede extenderse a sí mismo, y quienes dominan Lisp lo llaman un programmable programming language
  • La herramienta clave es macro
    • No se limita a eliminar código repetitivo como los macros de C, Rust o Swift
    • Los macros de Lisp pueden crear nuevos componentes que pasan a formar parte del lenguaje
  • Common Lisp no incluye un operador while básico, pero se puede agregar directamente con defmacro
(defmacro while (condition &body body)
  `(loop while ,condition do
     (progn ,@body)))
  • Este macro while ejecuta varias instrucciones de body mientras condition sea verdadera
    • loop es un macro para escribir iteraciones complejas
    • progn ejecuta varias expresiones en orden y devuelve el resultado de la última
  • Como resultado, en vez de (loop while ... do (progn ...)) se puede usar la forma (while ...), lo que hace el código más corto y con una estructura parecida al while de C

La diferencia decisiva entre macro y función

  • Si se intenta crear el mismo comportamiento con una función fake-while, falla
(defun fake-while (condition body)
  (loop while condition do
    (funcall body)))
  • En una llamada a fake-while, los argumentos se evalúan primero
    • condition se convierte en el valor verdadero t
    • (print counter) dentro de progn se ejecuta y (decf counter) devuelve 2
    • body deja de ser un bloque de código y pasa a ser el valor 2
  • Luego funcall espera una función, pero recibe 2, así que se produce un error de tipo como The value 2 is not of type FUNCTION
  • En cambio, el macro while conserva condition y body sin evaluarlos de inmediato
    • Se puede comprobar el resultado de la expansión con macroexpand-1
    • El compilador recibe código ya expandido con la forma (LOOP WHILE ... DO (PROGN ...))
  • A diferencia de una función, un macro no evalúa los argumentos por adelantado, sino que los trata como datos puros, y por eso esta transformación es posible

Listas, s-expression y homoiconicidad

  • Un programa en Lisp está compuesto por una secuencia de symbolic expressions, es decir, s-expressions
  • Las s-expressions se dividen en dos tipos
    • átomos (atom): unidades de datos como números, cadenas o símbolos
    • listas (list): colecciones que contienen átomos u otras listas
  • El nombre Lisp viene de LISt Processing, y las instrucciones que forman el programa también se representan como listas
  • En Lisp, la lista es al mismo tiempo la estructura de datos principal y la forma de escribir código
    • A esta propiedad, donde tanto el código como los datos se representan como listas, se le llama homoiconicidad (homoiconicity)
  • La misma lista (+ 1 2) puede comportarse distinto según se evalúe o no
    • (+ 1 2) se evalúa como código y devuelve 3
    • '(+ 1 2) no se evalúa y se devuelve tal cual como lista de datos
  • Lisp usa notación polaca, colocando el nombre de la función como primer elemento de la lista y los argumentos después
  • Como la frontera entre código y datos es muy delgada, los macros pueden transformar el código fuente y crear programas que escriben programas

La abstracción de código que crean los macros

  • Al extender el lenguaje, se pueden crear componentes nuevos y más expresivos para dominios específicos del programa
  • El boilerplate repetitivo puede reemplazarse con macros personalizados para reducir código y ahorrar tiempo
  • También se pueden crear nuevas estructuras de control para manejar el acceso a recursos y la evaluación de formularios
  • Los macros generan código, mejoran el rendimiento y proporcionan abstracciones sintácticas que esconden código complejo y propenso a errores

Lisp como sistema vivo

  • Lisp se trata menos como un simple lenguaje de programación y más como un sistema vivo en ejecución
  • En lenguajes comunes, el flujo suele ser escribir código en el editor, compilarlo, ejecutarlo y luego observarlo, probarlo y depurarlo
  • En Lisp, primero se inicia un proceso de Lisp, luego se conecta uno al REPL y se carga el proyecto dentro de ese proceso
  • REPL significa Read-Eval-Print Loop, un entorno interactivo donde se evalúa código y se ve el resultado de inmediato
    • Funciona como una ventana al proceso de Lisp que está ejecutando el programa actual
  • Quienes desarrollan en Lisp siguen evaluando código dentro del proceso en ejecución y revisan los resultados directamente desde el REPL
    • pruebas de funciones individuales
    • consultas a bases de datos
    • inspección de variables
    • tareas de depuración también pueden hacerse desde el REPL
  • No hace falta detener el proceso de Lisp, así que puede seguir vivo durante semanas
  • Las funciones, macros y variables se definen y redefinen continuamente en la memoria interna, el entorno (environment), y a este flujo se le llama desarrollo guiado por REPL

Hot reloading en Lisp

  • En el frontend web es común la experiencia de hot reload del código JavaScript al guardar archivos o recargar la página
  • El hot reloading habitual depende de herramientas y técnicas aparte, como vigilancia de archivos, recompilación de módulos modificados e inyección de cambios por WebSocket
  • No todos los stacks de software ofrecen el mismo nivel de hot reloading
    • algunos frameworks de backend requieren recompilación
    • en entornos de escritorio y móviles la situación es mixta
    • los lenguajes de bajo nivel suelen necesitar compilación completa cada vez
  • En Lisp, el hot reloading no es una herramienta aparte, sino algo que surge de forma natural al evaluar código en un entorno vivo
    • al redefinir símbolos, funciones, datos y macros pasan a usar la nueva definición
    • se reduce la necesidad de detenerse y compilar, ejecutar pruebas por separado o usar depuradores especiales
  • Programar en Lisp se parece menos a ensamblar un programa y más a hacerlo evolucionar

Software extensible

  • La extensibilidad del lenguaje y el sistema vivo facilitan crear software extensible en Lisp
  • Los programas de escritorio tradicionales suelen ampliarse mediante plugins o lenguajes de scripting
    • quienes desarrollan deben diseñar y mantener el sistema de extensiones
    • quienes usan el sistema deben aprender una API específica para escribir plugins o extensiones
  • En Lisp, al encapsular comportamientos con macros y volverlos fáciles de reutilizar, se termina escribiendo DSL de forma natural
  • Para hacer un software extensible, basta con permitir que las personas usuarias escriban con el DSL interno creado dentro del sistema
  • En el ejemplo de un servidor CMS, se puede exponer a los usuarios un macro html para generar páginas web del lado del servidor
    • las personas usuarias pueden usar directamente variables de Lisp, bucles dolist y formateo de cadenas con format
    • no necesitan aprender una sintaxis aparte como {{ user_name }} o {% for %}, como ocurre en lenguajes de plantillas tradicionales
  • Ese DSL hereda intactas las capacidades de Lisp: condicionales, recursión, funciones de orden superior y depuración paso a paso desde el REPL
  • En el ejemplo de software para gráficos matemáticos, se puede exponer un DSL para fórmulas y dibujo, de modo que las personas usuarias tracen curvas y puntos con código breve

Casos reales y el lugar de Lisp

  • AutoCAD usa AutoLISP para automatizar tareas repetitivas y generar geometría compleja
  • Emacs es un editor de texto altamente extensible, implementado en gran parte con su propio dialecto de Lisp
    • lector de PDF
    • navegador web
    • cliente de correo electrónico
    • lector de RSS
    • multiplexor de terminal
    • cliente Git
    • reproductor de música
    • cliente de chat
    • hoja de cálculo
    • cliente IRC
    • incluso se enumeran casos donde se ha extendido hasta funcionar como administrador de ventanas de escritorio
  • R. M. Stallman valoró Lisp como un lenguaje que permite entender qué significa un lenguaje de programación poderoso y elegante
  • La expectativa de que Lisp algún día se volviera tan ampliamente usado como un lenguaje base no se cumplió, y parece poco probable que ocurra en el futuro
  • Aun así, Lisp ha sobrevivido desde la década de 1960 y se ha convertido en el lenguaje de programación en activo más antiguo después de Fortran
  • El valor de Lisp no proviene de una sola función aislada como la extensibilidad, el entorno interactivo o el REPL, sino de la combinación de todo eso

1 comentarios

 
GN⁺ 3 시간 전
Opiniones de Hacker News
  • La programación existe sobre la tensión entre el lado luminoso y el lado oscuro.
    El lado luminoso es el que impide que los programadores cometan errores: elimina goto, incorpora tipos estáticos y hace que los bugs no puedan expresarse.
    El lado oscuro es el que les da poder a los programadores: permite libremente macros, sobrecarga de operadores, código automodificable e incluso expresiones regulares multilínea.
    Lisp es claramente del lado oscuro en el sentido de que permite que el programador haga cualquier cosa, pero es interesante que aun así también sea respetado por los programadores del lado luminoso. Tal vez la simplicidad del lenguaje lo hace parecer platónico y casi imposible de corromper, o quizá Lisp es tan puro que abarca a ambos lados, como un dios que dio origen al universo de la programación.

    • Parafraseando algo que he visto en el debate entre tipado dinámico y estático: los lenguajes permisivos empoderan al programador que desarrolla solo, pero para el desarrollo en equipo se necesitan lenguajes más restrictivos.
      No puedes elegir con quién vas a trabajar, y el nivel dentro del equipo tampoco es parejo. Cuando un colega menos experimentado comete errores, cuanto más permisivo sea el lenguaje, mayores serán las consecuencias.
      Por eso se necesitan revisiones de código, pero entonces conviertes a los programadores experimentados en docentes. Parte del tiempo invertido en mejorar la habilidad de otros programadores se desperdicia porque los programadores pueden entrar y salir en cualquier momento. La IA podría cambiar esta dinámica.
      Al final, lo central es mantener equipos pequeños y experimentados, pero por la política interna de las empresas no es fácil. Por ejemplo, suelen aparecer enfoques como sumar más desarrolladores por consideraciones del bus factor o para acortar los tiempos de lanzamiento.
    • Como Lisp suele tener recolección de basura precisa, también podría verse como más cercano al lado luminoso. Si se considera la verificación de tipos en tiempo de ejecución como seguridad de tipos, también es bastante seguro en cuanto a tipos.
      Los sistemas de alta confiabilidad también se escriben en Erlang, que, si uno entrecierra los ojos, puede verse como otro dialecto de Lisp. Incluso existe LFE, una versión basada en expresiones S que es un Erlang al estilo Lisp.
      El núcleo de la confiabilidad de Erlang no está en una prevención de errores excepcional, sino en la recuperación ante errores. Me gusta la clasificación luminoso/oscuro en sí.
    • Creo que una gran característica de Lisp es que, salvo por la asignación a variables mutables, básicamente es declarativo, no un paradigma imperativo.
      Aunque no tenga tipos estáticos y las macros puedan volverse un caos, la línea base del pensamiento declarativo y funcional es mucho más fuerte, lo que da un mejor punto de partida para pensar y razonar sobre los programas con mayor claridad.
    • Me pregunto de qué lado quedaría Malbolge. ¿Y Python, Haskell, Idris, Clean, C y K?
      La distinción luminoso/oscuro parece demasiado simplificada. El equilibrio de los lenguajes de programación es un tema muy complejo e interesante.
      Tras experimentar durante años con varios lenguajes, al final resultó ser una cuestión de contexto de uso, gusto personal y objetivos. No existe “el mejor lenguaje de programación de todos los tiempos”, ni tampoco “el mejor para programar del lado luminoso” o “el mejor para programar del lado oscuro”.
      En la pintura artística tampoco existe algo como un lado luminoso/oscuro. Sin duda hay cuadros más grandes, pero no existe “el mejor cuadro” que todas las personas sientan como el más bello en comparación con todos los demás.
      https://en.wikipedia.org/wiki/Malbolge
      https://en.wikipedia.org/wiki/Clean_(programming_language)
      https://en.wikipedia.org/wiki/K_(programming_language)
    • Parece que mezclaron lo luminoso y lo oscuro. La restricción y la disciplina de “el creador sabe mejor que nadie” son el lado oscuro; confiarle el poder a las personas es el lado luminoso.
  • En los últimos meses salieron excelentes editores y herramientas nuevos, así que no hay que perdérselos.
    Mine es una app de descarga única que ofrece todo lo necesario para experimentar un flujo de desarrollo interactivo e incremental, incluido hot reloading y depuración instantánea. Es para CL y Coalton.
    https://coalton-lang.github.io/20260424-mine/
    OLIVE es un plugin artesanal para VSCode, e ICL es un nuevo REPL para terminal y navegador que ofrece funciones avanzadas. Como bonus, también hay un kernel de JupyterLite basado en JSCL, que corre 100% en el navegador.
    Todo se puede ver aquí: https://lispcookbook.github.io/cl-cookbook/editor-support.ht...

    • No encuentro el código fuente de mine. ¿Hay algún enlace?
  • Parece que el sitio web tiene un bug de resaltado de sintaxis. Los fragmentos de código incluidos en el texto aparecen en negro, y si los seleccionas con el mouse se puede ver el texto real.
    Veo el mismo bug en Chrome de escritorio y en Safari para iPad.

    • Es un caso clásico de que, al cambiar el color de fondo, siempre hay que definir también el color de primer plano. Si no, terminas con un bloque de texto negro sobre fondo negro. Si el navegador está en modo oscuro, probablemente se verá bien.
      La solución alternativa es abrir un elemento de código en el depurador del navegador y agregar color: white al estilo :not(pre) > code.
    • Corregí el error apenas leí el comentario.
    • ¿Chrome en MacOS? En Firefox, Chromium y Brave en Linux los bloques de código se ven bien. Creo que probablemente todos usan Qt.
    • Me pasa lo mismo tanto en Firefox como en Chrome.
    • Al principio pensé que el artículo estaba censurado.
  • Hay muchos textos que elogian las ventajas de Lisp. También me gustaría ver textos que critiquen con calma a Lisp, sus ideas y su lugar en el ecosistema de lenguajes.
    Estos textos, o los textos de PG a los que hacen referencia, al final se acercan a un “quien sabe, sabe”. Entiendo su atractivo, y también entiendo las afirmaciones explícitas e implícitas que hace este texto.
    La programación de computadoras ha madurado bastante en los últimos 60 años. Me gustaría ver más textos con un análisis más meditado.

    • Como lenguaje, Lisp es excelente, pero su ecosistema es limitado. Tiene dos defectos. Uno es que es demasiado abierto, de modo que, sin talento y disciplina, uno puede caer en la madriguera de hacks interesantes de Lisp y no terminar el trabajo real. Otros lenguajes también tienen este problema, pero creo que Lisp lo tiene más.
      El segundo defecto es que consume años del tiempo de gente suficientemente competente, y los resultados no justifican esa inversión de tiempo. Algo como Python también es suficiente. Pienso que ojalá la mayor parte del tiempo dedicado a Lisp se hubiera usado en otra cosa.
    • La expresión “la programación ha madurado bastante” suena como si Lisp se hubiera quedado detenido en algún lugar del pasado.
      Clojure, Clojurescript, Clojure-Dart, Fennel, Jade, Jank, Jolt y Coalton son lenguajes relativamente recientes y siguen evolucionando. Esos son solo los que se me vienen a la mente ahora, y hay muchos más.
      Lisp, en cierto sentido, no es un lenguaje de programación sino una idea. Influyó en casi todos los lenguajes de programación que usamos hoy, y sigue haciéndolo. Es difícil criticar “con calma” una idea; es parecido a criticar la teoría de grupos. Lo que sí se puede discutir son las ventajas y desventajas de implementaciones concretas de esa idea.
    • La maldición de Lisp: https://www.winestockwebdesign.com/Essays/Lisp_Curse.html
    • En un lenguaje actual, la concurrencia estandarizada es un requisito básico. CL no tiene un async/await estandarizado ni un modelo de concurrencia. El estándar no se actualiza desde 1995, así que tampoco va a ocurrir en el futuro.
    • Parece que Lisp tiene algo así como una orientación de la manija.
      A algunas personas les resulta mentalmente atractivo. Lo compararía con un género musical realmente de nicho. A poca gente le gusta, pero a quienes les gusta, les gusta con mucha intensidad. Es como el Stockhausen de la programación.
      Básicamente es un fandom. Un fandom sorprendentemente duradero, pero nunca logró abrirse paso de forma masiva, y es poco probable que lo haga en el futuro. Ahora su posición es aún peor. Si estás armado con LLM y no te interesa demasiado el código en sí, ¿por qué pedirías específicamente que lo escriba en Lisp?
  • Llevo tanto tiempo usando Lisp que dejé de apreciar bien sus funcionalidades. Pero luego, cuando veo con shock y horror cómo la gente se arruina a sí misma en lenguajes populares y económicamente menos riesgosos, de pronto vuelvo a sentir el valor de Lisp.

  • En entornos comerciales, los lenguajes específicos de dominio son un antipatrón. Alguien crea un lenguaje específico de dominio con poca documentación y que solo esa persona entiende, y luego se va.
    Los programadores que vienen después tienen que esforzarse por descifrar ese lenguaje extraño. Casi siempre es mejor usar estructuras y funciones de un lenguaje estándar. El código se lee más de lo que se escribe.

    • Cada vez que creas una función, en cierto modo estás creando tu propio lenguaje específico para ese dominio.
      Es muy probable que lo que realmente se critique sea la falta de transparencia referencial. Para ser justos, es un problema en muchos lenguajes, incluido Lisp.
    • En Lisp, los programadores que vienen después simplemente pueden mirar la expansión de macros. Con herramientas modernas, si quieren, también pueden verla dentro del editor, como texto alternativo en el mismo archivo fuente, conectados a un entorno Lisp vivo.
      Un buen ejemplo es la propia macro LOOP de Common Lisp. Si el uso que alguien le da es difícil de entender, se le puede pedir a Lisp que la expanda a llamadas básicas más verbosas que no sean LOOP, y no hace falta entender LOOP en absoluto. De hecho, también se puede reemplazar el formulario LOOP por el código expandido.
      Esta es una diferencia clave frente a la mayoría de los demás lenguajes, donde el código de un lenguaje específico de dominio en realidad suele ser una estructura de datos interpretada.
  • Los Lisp tienen cosas realmente potentes y únicas, pero ojalá estos textos dejaran de incluir siempre el REPL y la recarga en caliente.
    El REPL es desde hace mucho tiempo un requisito básico en los lenguajes interpretados, e incluso en algunos lenguajes compilados. La recarga en caliente no es única ni se usa particularmente de forma generalizada. Como hay que manejar estado y parches, hay una razón por la que restablecer todo para facilitar el razonamiento se considera una buena práctica.

    • Cuando estaba aprendiendo Clojure, yo también pensaba eso. Mucho después me di cuenta de que, cuando la gente de Lisp habla de REPL, normalmente no se refiere tanto a una CLI interactiva para evaluar comandos con facilidad, sino a la capacidad de conectar el programa a una sesión viva para evaluar rápidamente formularios dentro del editor de texto, en el contexto de la aplicación en ejecución.
      Por eso permite un desarrollo mucho más interactivo que otros lenguajes interpretados.
    • En Dart/Flutter, la recarga en caliente se usa muchísimo. Cuando se escribe código de UI con un framework de estilo reactivo y el renderizado de la UI parece “crear una UI nueva desde cero en cada frame”, es más fácil tener una intuición sobre qué se recarga y qué no.
      Por supuesto, no es perfecto. Pero funciona muy bien para el tipo de cambios que se hacen al iterar y mejorar la experiencia de usuario.
    • En general, estoy de acuerdo.
      Aun así, vale la pena destacar que buena parte de los aspectos avanzados de la recarga en caliente ya fueron abordados en Common Lisp. Lo mismo con el REPL: no se usa principalmente como un lugar donde escribir directamente, sino como una interfaz muy potente para que las herramientas interactúen con una imagen en ejecución.
      De todos modos, coincido en que el simple hecho de que existan no los hace tan especiales hoy en día.
    • No todos los dialectos de Lisp tienen un sistema de hot patching bien desarrollado. Los sistemas orientados a objetos deben diseñarse cuidadosamente para eso.
      ¿Qué hacer si una definición de clase fue reemplazada por una recarga, pero todavía quedan instancias existentes? Los dialectos de Common Lisp tienen respuestas útiles para estas preguntas, pero no todos los Lisp que uno se encuentre necesariamente las tendrán.
      Bash también soporta recarga en caliente. Alguna vez desarrollé un módulo que se actualizaba en el lugar usando source, así:
      $ . /path/to/script.sh
    • En general, el dolor de gestionar hot patches depende mucho de la estructura de la base de código y de la razón por la que se quiere hacer hot patching. Si se trata de una arquitectura de estructura de arreglos o de corregir errores lógicos en tiempo de ejecución, no es gran cosa.
      Su utilidad es limitada, pero si se parte de la idea de que se va a usar mucho, esas limitaciones empiezan a desaparecer bastante rápido.
  • En lo personal, ya superé esa etapa. Probé Common Lisp, Forth y Haskell, y disfruté leer On Lisp y Let Over Lambda
    Ahora creo que el mejor lenguaje de programación es el Triage Calculus de Barry Jay. Se parece a la lógica combinatoria o al cálculo lambda sin tipos
    Pero, a diferencia del cálculo lambda, Triage Calculus tiene cita e introspección incorporadas, parecidas a CAR y CDR de Lisp, lo que facilita agregar verificación de tipos. Por eso en TC puedes tener la sintaxis que quieras, siempre que construyas las abstracciones correctas. Es el verdadero lenguaje de programación definitivo
    TC muestra que la distinción entre, por un lado, las funciones y la sintaxis del lenguaje de programación, y por otro, las definiciones de funciones/API de la biblioteca estándar o del código de usuario, es una falsa dicotomía. Cada vez que escribes código pensado para reutilizarse, estás agregando algo al lenguaje. Todo esto puede expresarse como algún término de TC
    Todas las discusiones sobre sintaxis son cuestión de costumbre. Aunque una función sintáctica que sí quisiera en TC es una abstracción let over lambda, porque ordenar combinadores a mano es algo molesto

  • Muy buen artículo
    Antes pensaba que algún día todos usarían Lisp y que, cuando hubiera buenas herramientas y bibliotecas, todo sería genial. De hecho, mi plan para después de jubilarme era crear bibliotecas de alta calidad para lenguajes Lisp, para acelerar ese proceso
    ¿Será que el auge de la IA pone fin a ese sueño? ¿Otra vez resolvimos el problema agregando más porquerías? ¿En vez de que una IA superinteligente escriba código en el mejor lenguaje de programación posible, simplemente va a escupir montones de código Python y empujar hasta que funcione?
    No sé si eso importa. Simplemente quería un mundo con elegancia

    • Siempre me pregunté qué habría pasado con el primer “Interface Builder”
      “Jean-Marie Hullot, mientras trabajaba en INRIA, creó ‘SOS Interface’ para Macintosh, escrito en Lisp, y fue el primer ‘interface builder’ moderno”
      https://denninginstitute.com/itcore/userinterface/GUIHistory...
      Me pregunto qué habría pasado si eso se hubiera convertido en un producto principal para Mac, en lugar de pasar a NeXT y usarse junto con Objective-C
      LISP me quedaba bien. En la clase universitaria de lenguajes comparados fui el único que completó todas las tareas de LISP, y haber aprendido LISP también me ayudó mucho a usar TeX
      Lo que quisiera es un toolkit GUI nativo o multiplataforma decente y open source, y una forma sencilla de distribuir proyectos como código compilado ejecutable independiente
    • El lenguaje nunca es la respuesta. Lisp no es superior a Visual Basic. Ambos son Turing completos
      Los humanos pueden expresar buenas ideas con cualquiera de los dos. Es mejor pensar en los lenguajes como herramientas. Un taladro de impacto no es superior a un taladro rotativo simple. Para construir una terraza, tal vez el taladro de impacto sea más adecuado, pero ambos pueden hacer el trabajo
  • Pensé que este artículo iba a ser https://web.archive.org/web/20120106121645/http://wiki.alu.o...
    Me trajo recuerdos de seguir comp.lang.lisp. Era casi como un drama. No solo había magia de programación, sino también muchas personalidades fuertes y acontecimientos