3 puntos por GN⁺ 2025-11-04 | 1 comentarios | Compartir por WhatsApp
  • Un análisis del código en C de 50 líneas del intérprete del lenguaje K creado por Arthur Whitney, junto con una interpretación de su estilo de programación único
  • El código incluye muchas estructuras experimentales poco comunes en C convencional, como sintaxis comprimida basada en macros, extensiones no estándar de C y uso implícito de argumentos
  • El autor interpreta directamente el significado de cada macro y función, y explora la filosofía de los lenguajes de la familia APL y las ventajas y desventajas de la alta densidad de código
  • Entre las ventajas del código se señalan su brevedad y gran capacidad de composición; entre las desventajas, la sintaxis no estándar y la menor legibilidad
  • En conclusión, este código se valora como un caso que muestra la importancia de escribir código después de comprender por completo el problema, más que simplemente “cómo escribir más corto”

Arthur Whitney y su código

  • Arthur Whitney es un científico de la computación que diseñó los lenguajes A, K y Q y las bases de datos kdb y Shakti
    • kdb es una base de datos de series temporales ultrarrápida usada en finanzas, y Shakti es una versión aún más rápida diseñada para procesar datasets de hasta 1 billón de filas
  • Sus lenguajes son lenguajes basados en arreglos fuertemente influenciados por APL, con énfasis en la concisión y la expresividad matemática
  • El enfoque del texto no está en las aplicaciones financieras, sino en analizar el estilo único del código en C escrito por Whitney

Estructura del intérprete de K de 50 líneas

  • El repositorio público ksimple incluye un intérprete en C de unas 50 líneas que Whitney escribió en pocos días
  • El núcleo del código está compuesto por dos archivos, a.h y a.c, y se caracteriza por la abreviación de definiciones de funciones mediante macros y por una estructura que usa punteros como si fueran enteros
  • La sentencia typedef char*s,c; define s como puntero a cadena y c como tipo carácter
  • s Q=(s)128; es un ejemplo de uso de un puntero como si fuera un entero, y en todo el código Q se usa como un valor especial que representa un estado de error
  • Se usan ampliamente extensiones de GCC como la statement expression con forma ({e;}) y el operador ?:

Significado de las principales macros y funciones

  • #define _(e...) ({e;}) : macro que agrupa múltiples sentencias en una sola expresión
  • #define i(n,e) : forma abreviada de repetición que expresa un bucle for en una sola línea
  • #define Q(e) y similares son macros de manejo de errores; Qr, Qd y Qz devuelven errores de rank, domain y not-yet-implemented, respectivamente
  • Las macros _s, _i, f, F simplifican la declaración de funciones y usan implícitamente los argumentos x y a
  • ax, ix, nx y otras son macros para identificar tipos de datos e indexar; ax determina si “x es un átomo”
  • f(w,write(1,ax?&x:x,ax?1:strlen(x));x) es una función de salida: si es un átomo, lo imprime como carácter; si es un vector, como cadena

Cómo funciona el intérprete

  • La función m(x) realiza asignación de memoria y genera un puntero con información de longitud incluida; la longitud máxima del vector es de 255 bytes
  • La macro g(a,v) unifica el manejo de operaciones átomo/vector y sirve como base para funciones como not, sub, At y _A
  • La macro G(f,o) genera automáticamente funciones para operadores binarios y soporta operaciones como <, ==, +, *, & y |
  • cat, rev, cnt, Tak y otras son funciones de manipulación de vectores; rev genera índices en orden inverso usando la función ind
  • La función e() es un evaluador recursivo que lee la cadena de derecha a izquierda y procesa variables de un solo carácter, números y operadores
  • main() recibe entrada, la evalúa con e() y luego imprime el resultado en forma de bucle REPL

Evaluación del estilo de código

  • Ventajas
    • Un conjunto conciso de operaciones primitivas compuesto por macros combinables
    • La brevedad del código permite captar toda la lógica de un vistazo sin necesidad de hacer scroll
    • La expresión de alta densidad comprime la estructura lógica del código
  • Desventajas
    • Manejo de tipos sin significado semántico al usar char* como si fuera un entero
    • Menor legibilidad por el uso directo de códigos ASCII, operadores ternarios complejos y sintaxis no estándar
    • Los argumentos implícitos y los nombres de variables cortos dificultan entender la intención
  • Elementos neutrales
    • La sintaxis exclusiva de GCC (?:, statement expression) es interesante, pero reduce la portabilidad
    • El uso de argumentos implícitos puede ser útil en código pequeño, pero en código grande puede generar confusión
    • Los nombres cortos son eficientes una vez que uno se acostumbra, pero transmiten poco significado

Conclusión y lecciones

  • Este código no trata simplemente de “cómo escribir más corto”, sino de una forma de pensar en la que se escribe código después de comprender por completo el problema
  • El código de Whitney es la traducción a código de un modelo matemático ya terminado, es decir, “el resultado de expresar el pensamiento en código”
  • El autor reflexiona sobre su hábito de intentar resolver el problema dentro del propio código y, de cara al futuro, enfatiza la importancia del modelado conceptual y de ordenar las ideas antes de programar
  • En última instancia, el experimento se resume como una experiencia para entrenar la capacidad de leer código y explorar el equilibrio entre densidad de código y claridad de pensamiento

Ideas para experimentos futuros

  • Propuestas para ampliar el intérprete:
    • Soporte para vectores de punto flotante
    • Procesamiento de más de 255 elementos
    • Números y nombres de variables de varios dígitos/caracteres
    • Literales de arreglos e ignorar espacios en blanco
    • Agregar gestión de memoria y funciones de indicación de errores
    • Completar funciones no implementadas
  • Estas ampliaciones podrían convertirse en un experimento para desarrollarlo hacia un lenguaje realmente utilizable manteniendo el estilo de código a lo Whitney

1 comentarios

 
GN⁺ 2025-11-04
Comentarios en Hacker News
  • Los macros en este código sirven para comprimir operaciones comunes Yo leí primero J Incunabulum y luego vi este código, pero si un programador acostumbrado a C empieza a leer desde la mitad, las definiciones de macros del principio pueden resultar confusas Como los macros se construyen unos sobre otros, el código sube rápidamente por la escalera de la abstracción En particular me gusta el macro Iterate (i), porque reduce un bucle verboso a una sola letra La razón por la que este tipo de código denso es difícil de leer es que crea un montón de abstracciones en unas cuantas decenas de líneas y las usa de inmediato Por eso hay que leerlo despacio, carácter por carácter Desde la perspectiva de alguien que ha trabajado en codebases enormes compuestos por cientos de archivos delgados, esta compresión extrema hasta se siente refrescante

    • A mí me pasó algo parecido al leer Incunabulum, pero cuando reemplacé los nombres de variables por emojis se volvió mucho más fácil de entender Como puede verse en la imagen del código en versión emoji, parte del problema no es solo la densidad de información, sino también la forma de los caracteres (orthography) Los lenguajes modernos no permiten usar símbolos o emojis en identificadores, pero si esa distinción visual fuera posible sería mucho más fácil de leer Además, la mayoría de los editores usan syntax highlighting por tipo de sintaxis, pero muchas veces es más útil un coloreado basado en tokens (un color único para cada identificador) Un ejemplo es el “hashed syntax highlighting” de Sublime Text Al cambiarlo así, la estructura del código se volvió evidente de un vistazo
    • Parece que los desarrolladores más bien prefieren codebases gigantes A mí me gusta una estructura donde puedas buscar de inmediato con grep *.[ch] sin subdirectorios Los proyectos de Java en particular tienen demasiados archivos pequeños y con muy poco contenido, así que es difícil encontrar algo Con un IDE quizá sea mejor, pero yo no uso Whitney dijo en una entrevista que quería meter todo el código en una sola página, y que su “IDE” era la consola de Windows y Notepad
  • Para entender el código en C de Arthur Whitney, primero hay que aprender un lenguaje de la familia APL Si no, solo parece un estilo raro de C Lo que Whitney intenta es usar C como si fuera APL El estilo sin espacios, con nombres de una sola letra y funciones de una sola línea es igual en APL Es parecido a cuando un programador de Pascal usa algo como #define begin {, pero Whitney es mucho más original que eso

    • Incluso desde la perspectiva de alguien que usa APL, esto se ve raro El lenguaje K creado por Whitney sí usa este estilo, pero las funciones de una sola línea no eran posibles en el APL tradicional APL no tiene macros, ni operador ternario, ni nombres de variables implícitos La esencia de APL son las operaciones sobre arreglos inmutables, y el estilo de C de Whitney es distinto de esa filosofía
    • Sobre la frase “parece un programador de Pascal pasándose a C y haciendo #define begin {”, alguien bromea: “ah, como Stephen Bourne”
    • Al principio parecía un lenguaje funcional, pero pronto hizo recordar el horror del preprocesador de C
    • Ya desde la introducción del artículo se explica que “el C de Whitney se inspiró en APL” Es una observación de que hay muchos comentarios que solo resumen lo mismo
    • Aprender J también podría ser buena idea Es más accesible que APL y usa símbolos que se pueden escribir con un teclado normal
  • Mientras buscaba Shakti vi que el enlace de Wikipedia redirige a k.nyc, y la página tiene solo una letra: ‘k’ Al ver el código fuente, de verdad era solo `k

` Parece una versión HTML del minimalismo al estilo Whitney: quitar todo lo innecesario y dejar que lo implícito lo resuelva el compilador

  • k

  • Esta entrada del blog, independientemente de cómo se evalúe el estilo de programación de Whitney, es un análisis excelente Para haberla escrito en 8 horas, tiene bastante profundidad, y la parte de las conclusiones me impresionó especialmente Enlace al original

  • Esto me recordó el intento de Stephen Bourne de hacer que C fuera como Algol Si ves el ejemplo de mac.h y el ejemplo de expand.c, se siente una vibra parecida

  • En todos los campos existen las “best practices”, pero eso solo encaja bien en los casos promedio En situaciones específicas, a veces hasta conviene hacer lo contrario Al final, la sabiduría colectiva sirve como valor por defecto, pero cuando empiezas a pensar por tu cuenta es inevitable ver las grietas

    • Por eso no me gusta la expresión “best practice” En realidad no es más que un compromiso de nivel promedio Es un intercambio donde sacrificas eficiencia y rendimiento para ganar mantenibilidad y consistencia
    • Hacer un buen producto y la legibilidad o curva de aprendizaje de un codebase son cosas separadas Que una salga bien no significa que la otra vaya a seguirla automáticamente
  • Me gustó que mostrara una visión equilibrada sin ponerse agresivo con el código Fue una lectura entretenida y pienso volver a leerlo después

  • Me daba curiosidad si este estilo de programación corresponde a algún paradigma específico Casi nunca he visto código así en proyectos reales, salvo excepciones como el “business card ray tracer” El código fuente del lenguaje J creado por Whitney también tiene un estilo extremadamente comprimido

    • Sí, este es el estilo de programación propio de Whitney Lo usa de forma consistente en sus intérpretes de lenguajes de arreglos, y es famoso por meter implementaciones completas en unas cuantas páginas También hay un enlace a un meta comentario que recopila discusiones relacionadas en HN
    • A la frase “nunca he visto código así en la vida real”, alguien responde: “tuviste suerte” Esto ya no es C, sino más bien un DSL interno creado encima de C C es solo el primer objetivo de compilación
    • Se parece a lenguajes de la familia APL como J y K Usan símbolos no ASCII y pueden meter muchísima información en una sola página con una densidad extrema Una vez que te acostumbras, también tienen la ventaja de reducir capas de abstracción
    • También existe un video relacionado con co-dfns hecho con un enfoque parecido No es C, pero está escrito con un estilo de alta densidad similar
    • En broma, alguien dice que esto es “OCC (Obfuscated C Code)”
  • Si miras las siguientes definiciones de macros

    #define _(e...) ({e;})
    #define x(a,e...) _(s x=a;e)
    #define $(a,b) if(a)b;else
    #define i(n,e) {int $n=n;int i=0;for(;i