2 puntos por GN⁺ 2024-06-03 | 1 comentarios | Compartir por WhatsApp
  • En Spring Lisp Game Jam 2024 se enviaron 48 juegos, marcando un nuevo récord, y las obras participantes se dividieron claramente entre usar Lisp como capa encima del stack y construir el stack mismo con Lisp
  • El enfoque de glaseado pone Lisp como capa de scripting sobre programas basados en C/Rust/Lua para obtener resultados rápido, pero queda fuertemente atado al lenguaje estático y a su toolchain subyacente
  • El enfoque de pastel escribe la mayor parte del programa en Lisp y minimiza el C FFI para obtener un control más profundo, pero eleva el costo de implementar bibliotecas, escribir wrappers y desplegar en la web
  • En la Game Jam, Fennel+love2d y S7+raylib se acercan al glaseado, mientras que Guile+Chickadee es pastel, y Hoot+HTML5 canvas está más cerca del pastel gracias a su toolchain Wasm basado en Scheme
  • A medida que aumenta la proporción de Lisp, crecen el live hacking, la seguridad de memoria, la reducción de los límites entre Lisp/C y la capacidad de hackear; proyectos como Guix, Trial y Pre-Scheme muestran la misma dirección

Estado de las entregas en Spring Lisp Game Jam 2024

  • Spring Lisp Game Jam 2024 terminó hace una semana, y se enviaron 48 juegos, estableciendo un nuevo récord para la jam
  • Después, los participantes pasaron una semana jugando y evaluando los juegos de los demás
  • La distribución de las entregas por lenguaje fue la siguiente
    • Guile: 15, 31%
    • Fennel: 10, 21%
    • Clojure: 5, 10%
    • Common Lisp: 5, 10%
    • Racket: 4, 8%
    • Elisp: 4, 8%
    • S7: 3, 6%
    • Kawa: 1, 2%
    • Owl: 1, 2%
  • Proporción de Guile: {p:31}
  • La razón para no agrupar las implementaciones de Scheme en una sola categoría scheme es que la especificación de Scheme es pequeña, y Guile, Racket, S7 y Kawa son implementaciones con objetivos distintos entre sí
  • En esta jam, Guile registró por primera vez la mayor cantidad de entregas
    • 11 de los 15 juegos en Guile son juegos web hechos con Hoot
    • Hoot es un compilador de Scheme a WebAssembly en desarrollo en Spritely Institute
    • 2 de esos 11 son proyectos oficiales de Spritely
    • Antes de comenzar la jam, Spritely Institute pidió que probaran hacer juegos con Hoot, y muchos participantes respondieron
  • Normalmente, el lenguaje más popular en esta jam es Fennel, un Lisp que compila a Lua
  • Los 3 juegos hechos con S7 también sirven como ejemplos vinculados a formas de usar Lisp en desarrollo de juegos

Usar Lisp como glaseado

  • El patrón de glaseado es un enfoque que pone Lisp como un lenguaje de scripting sobre un “pastel” hecho en lenguajes estáticos como C o Rust
  • Normalmente se incrusta un intérprete de Lisp dentro de un programa más grande
  • Si quieres escribir en Lisp las partes de alto nivel de una aplicación, esta puede ser la ruta más rápida
    • Hace falta un intérprete o compilador adecuado
    • También debe existir una forma de añadir los hooks que la aplicación necesita
  • Si la parte principal del programa está escrita en C o Rust, se puede compilar a WebAssembly con emscripten y desplegar en la web
  • Permite obtener resultados satisfactorios con rapidez, pero queda fuertemente acoplado al lenguaje estático y a ese toolchain
  • Algunos ejemplos representativos son los siguientes
    • S7 es un Scheme embebible
    • Guile también puede usarse para extender programas en C, pero en vez de meter el intérprete dentro del ejecutable, normalmente se enlaza dinámicamente con libguile
    • Fennel aprovecha aplicaciones existentes con puntos de extensión en Lua y compila un lenguaje tipo Lisp a Lua

Usar Lisp como pastel

  • El patrón de pastel es un enfoque que implementa en Lisp la mayor parte posible del stack de software
  • En vez de meter Lisp dentro de un programa no-Lisp, se escribe la mayor parte del programa en Lisp
  • Si hace falta, se llaman bibliotecas compartidas mediante una interfaz de funciones externas (FFI), pero conviene minimizar ese uso
  • Toma más tiempo llegar al resultado
    • Hay que implementar por cuenta propia bibliotecas que no existan en la implementación de Lisp elegida
    • Hay que escribir wrappers para bibliotecas compartidas en C inevitables
    • Como el proyecto no se convierte fácilmente en un objetivo de emscripten, el despliegue web se vuelve más difícil
  • Este enfoque conecta con el debate clásico de embed vs. extend
  • Guile puede usarse también como glaseado, pero muestra más fortalezas cuando se usa como pastel
    • La visión inicial de Guile era añadir un intérprete de Scheme para volver otros programas más parecidos a Emacs
    • La buena práctica actual es escribir el programa en Scheme desde el inicio
  • Common Lisp también es un buen ejemplo del enfoque pastel
    • Implementaciones como SBCL ofrecen un buen C FFI
    • Pueden compilar a ejecutables nativos eficientes, reduciendo las situaciones en las que uno querría usar C por rendimiento

Glaseado y pastel vistos en casos de la Game Jam

  • Fennel + love2d

    • love2d ha sido durante mucho tiempo una opción popular para el desarrollo de juegos en solitario o en equipos pequeños
    • love2d es un programa en C++ con un intérprete de Lua embebido, así que es un buen objetivo para Fennel
    • Como la mayoría de las distribuciones Linux empaquetan love2d, es fácil ejecutar archivos .love de forma nativa
    • Gracias a emscripten, los juegos de love2d también pueden desplegarse en la web
    • Por eso la mayoría de los juegos en Fennel usan love2d
    • ./soko.bin y Gnomic Vengeance usan este stack
    • Fennel+love2d es un ejemplo completo de Lisp as icing
    • Fennel está en la parte más alta del stack, y prácticamente no hay una ruta para propagar Lisp hacia las capas inferiores
    • Hasta ahora es el stack de desarrollo de juegos con Lisp más exitoso
  • S7 + raylib

    • En esta jam, dos juegos, GhostHop y Life Predictor, usaron el stack S7+raylib
    • Raylib es una biblioteca en C con bindings para muchos lenguajes de alto nivel y ha ganado popularidad en los últimos años
    • S7 también está implementado en C y es fácil de incrustar, así que esta combinación se presta bien para desplegar en la web con emscripten
    • S7+raylib también es un caso de Lisp as icing, y valdrá la pena ver si gana más popularidad en futuras jams
  • Guile + Chickadee

    • Chickadee es una biblioteca de juegos para Guile, e implementa en Scheme casi todas las partes interesantes, incluido el renderizado
    • En jams recientes, dos juegos, Turbo Racer 3000 y Bloatrunner, fueron hechos con Chickadee
    • Guile+Chickadee es un caso de Lisp as cake
    • Chickadee envuelve algunas bibliotecas en C para tareas de bajo nivel como cargar imágenes, audio y tipografías, pero su propio código está escrito en Scheme puro
    • Las matemáticas de matrices y vectores también están implementadas completamente en Scheme
    • Ofrece un conjunto de primitivas de renderizado comparable al de love2d y raylib, y esto también está implementado en Scheme
    • Mientras muchas otras bibliotecas de juegos en Lisp suelen usar bibliotecas en C como nanosvg, Chickadee también muestra avances en implementar renderizado de gráficos vectoriales en Scheme
    • Chickadee ha llevado al límite al compilador y la máquina virtual de Guile, y en el proceso Guile también ha mejorado
    • Aun así, como su desarrollo ha recaído mayormente en una sola persona con tiempo libre limitado, ha tardado en alcanzar paridad funcional con bibliotecas de desarrollo de juegos más populares
    • Incluso en su estado actual funciona bastante bien para ese propósito
  • Hoot + HTML5 canvas

    • Hoot es un compilador de Scheme a WebAssembly
    • Hoot no compila la VM de Guile escrita en C a Wasm con emscripten
    • En cambio, implementa un toolchain completo de Wasm y un nuevo backend para el compilador de Guile que emite Wasm directamente
    • Hoot está escrito completamente en Scheme
    • A diferencia de los programas en C compilados con emscripten, que apuntan a Wasm 1.0 basado en memoria lineal, Hoot apunta a Wasm 2.0 con tipos de heap gestionados por GC
    • Gracias a esta estructura, los binarios de Hoot no incluyen un recolector de basura al distribuirse
    • Por eso son mucho más pequeños que un runtime Lisp compilado con emscripten
    • El binario Wasm de un juego hecho con Hoot pesa menos de 2MiB, y el love.wasm de un juego de love2d que se revisó pesaba casi 6MiB
    • Los programas de Hoot pueden interoperar fácilmente con JavaScript
      • Los objetos de Scheme pueden pasarse fácilmente a JavaScript
      • Los objetos de JavaScript también pueden pasarse a Scheme
      • Porque los objetos de ambos lados se gestionan en el mismo heap
    • Se puede acceder a las APIs del navegador como imports de Wasm, así que en juegos la API integrada de HTML5 canvas se vuelve una opción sencilla para renderizado 2D
    • En esta jam hubo 11 juegos que usaron Hoot, incluyendo Cirkoban y Lambda Dungeon
    • Hoot+HTML5 canvas es mayormente un pastel grueso con un poco de glaseado mezclado
    • Poner en marcha Hoot tomó un año y una cantidad considerable de financiamiento
    • Sin usar emscripten, construyó su propio toolchain y además extendió el compilador de Guile
    • También existe un intérprete de Wasm que corre sobre la VM de Guile
    • En cambio, la API de canvas es de muy alto nivel
    • Un enfoque más cercano al pastel sería invocar WebGL o WebGPU con el JS FFI de Hoot
    • Los planes a futuro apuntan a WebGL/WebGPU, y para hacerlo posible hacen falta mejoras en Wasm GC
    • Otro objetivo es portar Chickadee a Hoot para que los juegos de Chickadee puedan jugarse fácilmente tanto en nativo como en navegador, igual que los juegos de love2d

Límites y ventajas del enfoque pastel

  • El enfoque pastel también tiene límites claros
  • El entorno moderno no es el mundo de las máquinas Lisp, y hasta el pastel Lisp más alto suele estar sobre un pastel más grande hecho en C
  • Los sistemas Lisp modernos en algún punto llegan a capas inferiores
    • Emacs está sobre un núcleo en C
    • La VM de Guile está escrita en C
    • Hoot corre sobre grandes motores de JavaScript basados en C++, como V8
    • Los juegos de Hoot actualmente renderizan con HTML5 canvas, no con WebGL/WebGPU
    • Usar OpenGL requiere libGL
    • Chickadee usa guile-opengl, que llama a libGL mediante C FFI
    • También existen libpng, FreeType y otros
  • Reescribir todo en Lisp supone un problema grande de recursos
  • Aun así, recuperar parte del stack desde lenguajes como C sigue siendo una pequeña victoria
  • Las partes escritas en Lisp son más fáciles de hackear, y algunas incluso permiten live hacking mientras el programa está corriendo
  • Gracias a los runtimes gestionados por GC, por lo general se obtiene seguridad de memoria
  • Si disminuyen las llamadas FFI, baja el overhead de cruzar el límite entre Lisp y C y también mejora la seguridad
  • Cuanto mayor sea la proporción de Lisp en el stack, más cerca se está del pastel que del glaseado

Casos de pastel fuera de los juegos

  • Guix es un buen ejemplo de cuán poderoso puede volverse el enfoque pastel
  • Guix toma el modelo de empaquetado funcional del proyecto Nix y lo reimplementa reemplazando el lenguaje Nix por Guile
  • Las razones son el code staging, el compartir código y una mayor capacidad de hackeo
  • Guix también usa un sistema init escrito en Guile en lugar de systemd, y esa elección nace de las mismas razones
  • Al principio, Guix era fácil de criticar como una reinvención innecesaria de la rueda, pero después de 10 años su insistencia en maximizar el uso de Lisp se convirtió en una clave del éxito del proyecto
  • Los usuarios que aprenden los modismos de Guix y un poco de Guile obtienen una gran capacidad para configurar el sistema operativo como quieran
  • Guix puede verse como la experiencia más cercana a una máquina Lisp en hardware moderno
  • Del lado de Common Lisp, el motor de juegos Trial es un caso donde gran parte está implementada en Common Lisp en vez de limitarse a envolver bibliotecas en C
  • Proyectos como Pre-Scheme alimentan la esperanza de que incluso las capas por debajo de un runtime gestionado por GC algún día puedan implementarse en Lisp

Hacia construir más partes del stack con Lisp

  • La dirección está más cerca del pastel
  • Hace falta que existan más proyectos que sigan empujando los límites de lo que Lisp puede hacer
  • Lo más interesante en Lisp Game Jam, más que los juegos mismos, son esos pequeños avances que recuperan una rebanada del pastel desde el viejo y árido C
  • En el desarrollo de juegos con Guile, la idea es seguir empujando los límites con el proyecto Chickadee
  • La conclusión no es reescribir en Rust, sino reescribir en Lisp

1 comentarios

 
GN⁺ 2024-06-03
Opiniones en Hacker News
  • Me alegró aún más porque hoy casi no se ven textos que comparen enfoques de software de manera objetiva.
    Incluso cuando uno intenta encontrar artículos así, hoy en día muchas veces los resultados de búsqueda no logran superar el spam SEO.
    Janet parece haber sido creado para juegos y, sorprendentemente, también parece incluir muchos elementos “con baterías incluidas”, como servidores web o gráficos; por eso me sorprendió un poco no ver juegos que usen Janet.
    Creo que, en el ámbito de Lisp y los juegos, es un lenguaje al que vale la pena echarle un vistazo.

  • Me alegra que s7 esté recibiendo atención.
    Lo usé como Scheme en Scheme for Max, una extensión open source que incorpora un intérprete de Scheme en el entorno de música por computadora Max/MSP; está en algún punto entre Guile, Clojure y Common Lisp, pero es muy pequeño y fácil de embeber.
    También me gusta que tenga una licencia BSD, mucho más permisiva que la de Guile.
    Si te gustan las macros de Common Lisp con entornos de primera clase, es muy probable que s7 también te guste.
    También fue muy fácil de usar en WASM, y así lo estamos usando en un proyecto de educación musical.
    Tampoco fue difícil crear funciones genéricas para llamar funciones de JS desde Scheme y, a la inversa, llamar Scheme desde JS, así que todo el flujo resultó fluido.

    • Otro voto para s7.
      Embebimos con éxito s7 y SQLite como motor, salvo por los gráficos, en apps nativas para iOS y Android.
      Era muy rápido, tenía buen FFI, era estable y pequeño, y obtuvimos grandes beneficios en código compartido entre apps móviles, pruebas unitarias rapidísimas y un sistema de herramientas limpio.
      Al final, en móvil nos pasamos a Fennel, un Lisp más práctico.
      Mientras que casi éramos el único equipo usando s7 en móvil, Lua era mucho más común como lenguaje de extensión móvil, y el estado de compatibilidad con Scheme r7rs también influyó.
      Como usábamos Guile para desarrollo de escritorio y s7 para distribución, a menudo nos topábamos con incompatibilidades sutiles, por ejemplo el orden de evaluación de los parámetros.
      Tanto s7 como Fennel tienen proyectos y comunidades excelentes.
  • Recomiendo revisar especialmente Spritely Institute, incluido su blog.
    No quiero spoilear qué hacen, pero es un tema y una institución en los que vale la pena profundizar.
    Pasé más de 10 horas leyendo el blog, enlaces relacionados y proyectos.
    https://spritely.institute/archive/

    • Parece un lugar que atrae a buena gente y hace cosas bastante geniales.
  • Me pareció memorable el resumen: “No vivimos en el mundo de las máquinas Lisp, sino en el mundo de un PDP-11 glorificado”.
    Pero me pregunto si también existe algún “glaseado” para usar con sdl.

    • Es difícil llamar a las CPU tradicionales un PDP-11 glorificado.
      Son parecidas en el sentido de que son máquinas de von Neumann con memoria sin etiquetas, pero desde mediados de los 80, cuando los microprocesadores de 32 bits se volvieron comunes y la tecnología de compiladores Lisp evolucionó en consecuencia, las CPU tradicionales empezaron a superar a las máquinas Lisp.
      La parte de “memoria sin etiquetas” quizá tampoco se mantenga para siempre si miramos corrientes como CHERI, y hay margen para un gran regreso de las arquitecturas estilo LispM.
    • Me gustaba mucho el PDP-11.
      Durante varios años tuve una PDP-11/45 en la sala de estar y, más adelante, para reducir espacio, la cambié por varias H-11 LSI-11/2 con dos unidades de disquete de 8 pulgadas.
      El PDP-11 no solo fue una especie de protoplasma de Unix, sino que además estaba conceptualmente bien diseñado.
      Así como preferimos rutinas que “entran en una pantalla”, el pequeño espacio de direccionamiento directo del PDP-11 fomentaba módulos no demasiado grandes y promovía la modularidad.
      ¿Es insuficiente hoy? Claro, y en especial para big data sería doloroso.
      Aun así, hay razones conceptuales por las que el PDP-11 tuvo éxito y todavía deja huellas.
    • Irónicamente, ahora vamos hacia máquinas C con etiquetado de memoria por hardware.
      No hay otra forma de arreglar C, y hay demasiado código que no se va a reescribir.
    • Me gustó más el final: “¿Reescribirlo en Rust? ¡De ninguna manera! ¡Reescríbelo en Lisp!
    • Lisp no es adecuado para las CPU modernas debido a la jerarquía de memoria.
      Lisp trabaja principalmente con listas, y las listas pueden seguir punteros por distintas partes de la memoria.
      En las CPU antiguas, la memoria en general tenía tiempos de acceso aleatorio similares, así que no era un problema; pero las CPU modernas no pueden seguir punteros de memoria a la misma velocidad, y para el rendimiento hay que respetar las reglas de localidad.
      Por eso los algoritmos que usan cosas como arreglos de C o Fortran siempre serán más rápidos que sus versiones basadas en listas de Lisp.
  • Me entusiasman los avances recientes de Guile Scheme.
    A diferencia de la última vez que lo vi, pasó de ser un lenguaje interpretado a uno con un compilador en serio, y ahora también puede compilar a WASM con Hoot.
    Estoy familiarizado con Clojure, uLisp y Common Lisp, pero Guile Scheme se siente como si le hubieran quitado mucha de la carga innecesaria a Common Lisp; y, especialmente si Guix y Shepard se consolidan, me gustaría tener a mano un Lisp compilado.
    Me pregunto si hay buenos recursos para aprender Guile Scheme de manera efectiva, además de Little Lisper y SICP.

  • Lo leí con interés porque estoy pensando en usar Guile para algo que voy a construir próximamente.
    El trabajo del lado de WASM también parece haber salido bien.

  • Hace poco hice un prototipo de una pelea de jefe en 3D con Clojure: https://prototype-game.pages.dev

    • Excelente.
      Antes odiaba toda forma de desarrollo web, pero ClojureScript realmente lo volvió disfrutable para mí, y me gustaría que se usara más.
    • En móvil no se puede controlar.
      Lo volveré a intentar más tarde cuando esté frente a la PC.
    • Genial.
      Me da curiosidad qué biblioteca estás usando.
    • Lo digo con cariño por lo que hiciste: me recordó a Avatar - Legends of the Arena.
      Fue uno de los juegos que más me gustaban cuando era chico.
      https://www.youtube.com/watch?v=dcJFldES9dg
  • Aunque pedí que lo incluyeran en la tabla, quizá esto ya sea noticia vieja
    Referencias:
    https://lispy-gopher-show.itch.io/logos-lisp-legend/devlog/7...
    https://itch.io/post/10013482

  • Falta Janet, aun existiendo https://ianthehenry.com/posts/janet-game/
    El año de copyright del artículo aparece como 1899~1907, pero es una lástima que no se vea vintage

    • Parece que falta Janet
      Para scripting volví a Fennel, porque permite usar directamente muchas más bibliotecas de Lua y corre sin problemas casi en cualquier lado, incluso en a-Shell en el iPad
    • Consideré Janet muy seriamente, pero no vi un camino directo hacia mi objetivo de usar apps web y WebGL(ThreeJS)
      En este hilo había referencias útiles, y quizá lo vuelva a intentar más adelante: https://janet.zulipchat.com/#narrow/stream/409517-help/topic...
      Aunque ya tenía una ruta de producción probada, apenas alcancé a hacer algo jugable a tiempo, y decir “jugable” ya es bastante generoso
  • Me da mucha curiosidad qué juegos se hicieron con Emacs Lisp
    No es la primera opción que se me viene a la mente cuando pienso en programación de juegos