48 puntos por GN⁺ 10 일 전 | 5 comentarios | Compartir por WhatsApp
  • La diferencia entre los conjuntos de patrones fundamentales es más importante que la gramática individual, y los lenguajes de programación se dividen en siete ur-lenguajes según cómo manejan la iteración, la recursión y la composición.
  • ALGOL, Lisp, ML, Self, Forth, APL y Prolog son la clasificación central, y cada familia usa un lenguaje representativo como muestra de referencia para juzgar el linaje de otros lenguajes.
  • Un lenguaje nuevo que comparte un ur-lenguaje familiar es fácil de aprender, pero pasar a un ur-lenguaje desconocido requiere nuevas rutas de pensamiento y bastante tiempo de aprendizaje.
  • ALGOL se caracteriza por la organización de funciones centrada en asignación, condicionales y bucles; Lisp por los macros y el código como listas; ML por las funciones de primera clase y la recursión; Self por los objetos con paso de mensajes; Forth por una sintaxis basada en pila; APL por los arreglos n-dimensionales; y Prolog por los hechos y la estructura de búsqueda.
  • Para cualquier programador, dominar primero un lenguaje de la familia ALGOL es prioritario; luego conviene aprender SQL, y después seguir estudiando de forma constante ur-lenguajes desconocidos, lo que resulta ventajoso a largo plazo.

Los siete ur-lenguajes de la programación

  • Al elegir un lenguaje de programación, es más importante aprender patrones fundamentales que diferencias de gramática individuales, y entre lenguajes de familias similares las estructuras básicas como recorrer arreglos o combinaciones suelen tener casi la misma forma.
  • Los distintos grupos de lenguajes difieren mucho en cómo manejan la iteración, la recursión y la organización del programa, y estos conjuntos de patrones fundamentales forman ur-lenguajes distintos.
  • Aprender un lenguaje nuevo que comparte un ur-lenguaje familiar es una transición relativamente fácil, pero moverse a un ur-lenguaje desconocido exige bastante tiempo y nuevas rutas de pensamiento.
  • En el software, los ur-lenguajes reconocidos son siete: ALGOL, Lisp, ML, Self, Forth, APL y Prolog.
  • Cada ur-lenguaje se clasifica usando un lenguaje representativo específico como muestra de referencia, y los demás lenguajes se ubican comparándolos con esa muestra.
  • ALGOL

    • El programa está formado por una secuencia de asignaciones, condicionales y bucles, organizada en funciones.
    • Muchos lenguajes agregan aquí sistemas de módulos, formas de definir nuevos tipos de datos, polimorfismo y estructuras alternativas de control de flujo como excepciones o corutinas.
    • La mayoría de los lenguajes de programación ampliamente usados hoy pertenecen a la familia de este ur-lenguaje.
    • Dentro de ALGOL mismo se incluyen ALGOL 58, ALGOL 60, ALGOL W y ALGOL 68.
    • Assembly language, Fortran, C, C++, Python, Java, C#, Ruby, Pascal, JavaScript y Ada se conectan con esta familia.
    • Es el ur-lenguaje más antiguo, con un linaje que se remonta hasta la formalización de programas para la máquina analítica de Babbage por Ada Lovelace.
    • El lenguaje máquina y el ensamblador de las computadoras con arquitectura Eckert-Mauchly, que llevaron a EDVAC y las primeras Univac, así como los primeros intentos de lenguajes de alto nivel desde A-0 de Grace Hopper hasta Fortran y COBOL, tienen todos esta forma.
    • En la academia de los años 60 se desarrolló la programación estructurada para hacer estos lenguajes más manejables, y el resultado fue ALGOL 60; después, la mayoría de los miembros de la familia derivaron de ahí.
    • Con el tiempo, ha habido una tendencia a absorber funciones de otros ur-lenguajes.
      • En los años 80, conceptos de la familia Self se incorporaron en forma de clases y se usaron como medio para implementar definición de tipos de datos y polimorfismo.
      • Desde 2010 también aparecieron conceptos de la familia ML.
  • Lisp

    • Su sintaxis combina expresiones prefijas entre paréntesis con la representación por listas.
      • (+ 2 3)
      • (defun square (x) (* x x))
      • (* (square 3) 3)
    • La representación por listas entre paréntesis, con elementos separados por espacios, está integrada en el lenguaje, así que el propio código tiene forma de lista.
    • Los macros pueden recibir listas, modificarlas y pasar el código modificado al compilador, de modo que el programador puede redefinir el significado del lenguaje.
    • En la mayor parte de la escritura de código, suele comportarse como otros ur-lenguajes, normalmente ALGOL o ML, pero el sistema de macros es su rasgo distintivo.
    • Incluso la sintaxis loop de Common Lisp no es una función integrada del lenguaje, sino una forma definida mediante macros.
    • Hubo muchas variantes tempranas de Lisp, pero la comunidad llegó a un acuerdo en torno a Common Lisp.
    • Sussman y Steele exploraron hasta dónde se podía llegar solo con funciones y crearon Scheme.
    • También existen Lisps de propósito especial como Lush para cálculo numérico, AutoLISP como lenguaje de scripts de AutoCAD y Emacs Lisp para implementar el comportamiento del editor Emacs.
    • Más recientemente, Clojure ha surgido como la tercera gran rama de la familia Lisp.
    • Es la segunda familia de lenguajes más antigua que sigue en uso hoy, aparecida alrededor de un año después de Fortran.
    • Su punto de partida fue una pregunta matemática sobre cómo representar una estructura matemática capaz de evaluar sus propias expresiones.
    • John McCarthy dio una respuesta en 1958 y luego se implementó en computadoras.
    • El Lisp temprano, por su trasfondo matemático, no encajaba bien con las máquinas de la época; problemas de memoria y ciclos de CPU no existían en matemáticas, y se volvieron necesarias técnicas como la recolección de basura.
    • A fines de los 70 y comienzos de los 80 existieron máquinas diseñadas desde cero solo para ejecutar Lisp.
    • Muchos elementos de los entornos de desarrollo integrados actuales se inventaron en esas máquinas.
    • En ese mismo periodo, Lisp fue el principal medio de investigación en inteligencia artificial, y cuando el auge de la IA de los años 80 no dio resultados, Lisp también cayó junto con el campo en el invierno de la IA.
    • Aun así sobrevivió, y con el aumento del rendimiento de las computadoras y la adopción de sus funciones por otros lenguajes, las dificultades de implementación se redujeron.
  • ML

    • Las funciones son valores de primera clase, y el lenguaje cuenta con un sistema de tipos de la familia Hindley-Milner capaz de expresar varias funciones y uniones etiquetadas.
    • Toda iteración se realiza mediante recursión.
      • sum [] = 0
      • sum (x:xs) = x + sum xs
    • También se usa el enfoque de definir funciones que encapsulan patrones de iteración y reciben otras funciones para implementar el comportamiento.
      • map _ [] = []
      • map f (x:xs) = (f x) : (map f xs)
    • Algunos lenguajes, como Miranda y Haskell, usan evaluación diferida por defecto.
    • Otros expanden el sistema de tipos en varias direcciones.
      • OCaml intenta combinarse con conceptos del ur-lenguaje Self.
      • Agda e Idris adoptan sistemas de tipos dependientes que mezclan valores y tipos.
      • 1ML combina módulos y tipos.
    • De ML derivan CaML, Standard ML y OCaml.
    • También siguen familias relacionadas como Miranda, Haskell, Agda e Idris.
    • ML fue el metalenguaje de un programa de demostración de teoremas desarrollado en Cambridge, Reino Unido, y de ahí viene su nombre.
    • Después se extendió más allá de ese contexto y se difundió como lenguaje independiente, ganando popularidad en Europa, especialmente en Reino Unido y Francia.
  • Self

    • El programa está compuesto por un conjunto de objetos que se envían mensajes entre sí, y todo comportamiento se implementa de esa manera.
    • Los objetos nuevos se crean enviando mensajes a objetos existentes.
    • Incluso los condicionales se realizan mediante una variable que apunta a uno de dos objetos, true o false.
      • Esos dos objetos reciben un mensaje con como parámetros una función para ejecutar si es verdadero y otra si es falso.
      • El objeto true ejecuta la primera función, y el objeto false ejecuta la segunda.
      • El código que llama no sabe qué objeto es; simplemente envía un mensaje.
    • Los bucles funcionan igual, y si se crean los objetos adecuados y se colocan en los lugares adecuados, es posible redefinir por completo el significado del lenguaje.
    • Estos lenguajes normalmente guardan el código fuente no en archivos de texto sino en un entorno vivo.
    • El programador modifica el sistema en vivo y, en lugar de compilar archivos para construir el sistema, guarda ese estado.
    • Ejemplos importantes son Smalltalk y Self.
    • Muchos lenguajes adoptan solo parcialmente el paso de mensajes de esta familia, y a esa adopción parcial normalmente se le llama programación orientada a objetos.
    • La mayoría de ellos se basan en Smalltalk, y JavaScript es la excepción, pues deriva del sistema de objetos sin clases de Self.
    • El sistema de objetos de Common Lisp generaliza esto para que el runtime elija el código a ejecutar no solo según el objeto que recibe el mensaje, sino según todos los parámetros.
    • Erlang, en vez de mover el flujo de ejecución entre objetos, gira hacia hilos de ejecución paralelos que escuchan y envían mensajes de manera explícita.
    • El lenguaje original es Smalltalk, desarrollado en Xerox Parc a fines de los 70 y en los 80.
    • En los años 80 hubo varios sistemas comerciales de Smalltalk, e IBM usó Smalltalk para desarrollar la colección VisualAge de herramientas de programación para otros lenguajes.
    • Hoy Smalltalk sobrevive principalmente en la forma de Pharo Smalltalk de código abierto.
    • Se investigó mucho cómo ejecutar Smalltalk de forma rápida y eficiente, y el punto más alto fue el proyecto Strongtalk.
    • Los hallazgos de Strongtalk tienen importancia histórica porque sirvieron de base para el compilador JIT HotSpot de Java.
    • Smalltalk heredó de lenguajes anteriores las ideas de valor y tipo para implementar clases: todo objeto tenía una clase que le daba un tipo, y la clase creaba los objetos de ese tipo.
    • Self eliminó el concepto de clase y quedó compuesto solo por objetos.
    • Por ser una forma más pura, Self fue elegido como muestra representativa de este ur-lenguaje.
  • Forth

    • Los lenguajes de pila son una especie de imagen invertida de Lisp y comparten sintaxis con las calculadoras de notación polaca inversa de Hewlett Packard.
    • Tienen una pila de datos; cuando se escribe un literal como 42, se hace push en la pila, y los nombres de funciones operan sobre esa pila sin parámetros explícitos.
    • Incluso la aritmética simple aparece invertida, como 2 3 + 5 *.
    • Las definiciones de funciones también tienen una forma muy concisa.
      • En la mayoría de las variantes de Forth, : define una nueva palabra.
      • square equivale a llamar a dup y *.
      • dup duplica el elemento superior de la pila, y * multiplica los dos elementos superiores.
    • Puede interceptar el parser y reemplazarlo con su propio código, así que es posible sustituir toda la sintaxis.
    • Es común encontrar programas en Forth que definen pequeños lenguajes, como subconjuntos de Fortran o formas de parsear directamente diagramas ASCII que representan layouts de paquetes o transiciones de máquinas de estados.
    • Incluye varias variantes de Forth, además de PostScript, Factor y Joy.
    • Joy es un lenguaje puramente funcional que usa una formulación matemática de la composición en lugar de una pila.
    • Forth se escribió por primera vez en 1970 para el control de radiotelescopios.
    • Después se expandió ampliamente por los sistemas embebidos.
    • Los sistemas Forth son lo bastante fáciles de bootstrapear como para que existan decenas de variantes hechas por distintos programadores para sus propios fines.
    • PostScript apareció en los años 80 como un medio flexible para describir documentos en impresoras.
    • PostScript es más restringido que Forth en varios aspectos, pero define en el lenguaje operaciones básicas relacionadas con el layout gráfico.
  • APL

    • Todo en el lenguaje son arreglos n-dimensionales.
    • Los operadores se componen de uno o dos símbolos y realizan operaciones de alto nivel sobre arreglos completos.
    • La expresión es tan compacta que la propia secuencia de símbolos funciona como marca de la operación sin necesidad de darle otro nombre.
    • Por ejemplo, calcular el promedio de la variable x toma la forma (+⌿÷≢) x.
    • APL, J y K son ejemplos representativos.
    • Las operaciones de alto orden sobre arreglos se han exportado parcialmente a muchos entornos como MATLAB, NumPy y R.
    • APL comenzó como una notación matemática creada por Kenneth Iverson en los años 60 y luego se implementó en computadoras.
    • Desde entonces ha mantenido una base de apoyo de nicho entre quienes realizan cómputo pesado.
    • Su lenguaje descendiente K fue muy popular en entornos financieros.
  • Prolog

    • El programa está formado por un conjunto de hechos.
      • father(bob, ed).
      • father(bob, jane).
    • También se usan hechos no aterrizados que derivan otros hechos mediante variables.
      • grandfather(X, Y) :- father(X, Z), father(Z, Y).
    • El runtime de Prolog toma estos hechos y consultas, y realiza una búsqueda para encontrar resultados.
    • Si se elige adecuadamente la estructura de definición de hechos, se obtiene completitud de Turing.
    • En Prolog, los términos que forman los hechos son en sí mismos un tipo de dato único, que puede construirse y pasarse al runtime.
    • En eso ocupa una posición similar a los macros de Lisp o al reemplazo del parser en Forth.
    • Como los programas en Prolog son esencialmente búsqueda, su ajuste se centra en controlar el orden de búsqueda y cortar temprano los caminos sin resultados, como en una consulta a base de datos.
    • Incluye Prolog, Mercury y Kanren.
    • La mayor parte de la programación real en esta familia de ur-lenguajes se hace en Prolog mismo, y la comunidad mantiene una unidad muy fuerte.
    • En los años 70, lógicos franceses se dieron cuenta de que los programas podían expresarse en lógica de primer orden y empezaron a intentar implementarlo.
    • En los años 80, el proyecto japonés de computadoras de quinta generación apostó fuerte por Prolog, pero con el fracaso del proyecto también cayó la reputación de Prolog.
    • Aun así, durante décadas siguió la investigación para hacer más eficientes los runtimes de Prolog en la mayoría de los casos y para agregar nuevas funciones.
    • Al sumarse funciones como las restricciones numéricas, esto llevó a la programación lógica con restricciones.
    • Prolog sigue apareciendo en áreas de nicho.
      • La comprobación de tipos de Java estuvo implementada en Prolog durante varios años.
      • La herramienta temprana de búsqueda de código fuente de Facebook también se basó en Prolog.

Cómo aprovecharlo

  • Para la mayoría de los programadores, algunos o todos estos grupos de lenguajes pueden parecer muy ajenos, pero vale la pena invertir tiempo en cada uno por las rutas de pensamiento y las nuevas posibilidades que abren.
  • Desde la perspectiva de ALGOL, dos cosas pueden parecer completamente distintas, pero desde otra perspectiva muy a menudo la comparación es trivial.
  • Prioridad

    • Todo programador debería conocer bien un lenguaje de la familia ALGOL.
    • Después se recomienda aprender SQL, un lenguaje de la familia Prolog.
      • Ocupa el lugar de mayor utilidad en la carrera después de ALGOL.
  • Expansión posterior

    • Después de dominar esas dos familias, a largo plazo conviene aprender cada año un lenguaje nuevo de una familia de ur-lenguaje desconocida.
    • Los lenguajes sugeridos y el orden para cada familia tienen esta forma:
      • Lisp: PLT Racket
      • ML: Haskell
      • Self: Self
      • Prolog: Prolog
      • Forth: gForth
      • APL: K, usando ok
  • Ajuste del orden

    • Si haces mucho cálculo numérico, conviene aprender K más temprano.
    • Si haces mucha programación embebida, conviene aprender gForth más temprano.
    • Pero el orden en sí o exactamente qué lenguaje elegir no es lo importante.
    • Está perfectamente bien aprender Standard ML u OCaml en vez de Haskell, Common Lisp en vez de PLT Racket, o Factor en vez de gForth.
  • Complementos incluidos en las notas

    • Incluso después de aprender SQL, sigue siendo necesario aprender Prolog mismo.
      • Porque su forma real de uso es bastante distinta a SQL.
    • Se incluye la opinión de un lector de que una forma común de entender Forth en profundidad es crear uno mismo una implementación de Forth.
      • Se menciona que Forth es lo bastante pequeño como para que una sola persona pueda implementarlo desde cero en relativamente poco tiempo.
      • gForth es una buena implementación para aprender ANS Forth.
      • Como material de aprendizaje se menciona FORTH Fundamentals, Volume 1 de McCabe.
      • También se mencionan PygmyForth, eForth y colorForth como Forths para revisar.

5 comentarios

 
zkj9404 9 일 전

Está interesante.

 
tazuya 9 일 전

En la universidad aprendí materias de la carrera e hice tareas con la familia ALGOL, Lisp y Prolog, así que me trae muchos recuerdos.

 
mhcoma 9 일 전

Esos lenguajes dejaron mucho en los lenguajes de programación modernos de uso general,
pero de entre ellos, solo Forth parece haber tenido menos influencia.

 
click 9 일 전

Aunque no conozcas la notación prefija, programar con notación posfija sí que resulta demasiado incómodo.

 
GN⁺ 10 일 전
Comentarios de Hacker News
  • En la clase de PL de Tufts hice versiones mini, una por una, de las primeras 4 familias de lenguajes antes de imperativo, Lisp, ML, Smalltalk, y me dio gusto ver que ese proceso ahora también salió como libro de texto. Sí da pena que hayan quitado la parte de Prolog, porque antes sí estaba

    • Ojalá en algún momento aparezca por ahí, aunque sea en Internet Archive, una edición que incluya la sección faltante de Prolog
  • Si tuviera que corregir una sola cosa de la clasificación de este texto, diría que Ruby no es tanto de la familia Algol como claramente un lenguaje orientado a objetos. La influencia de Smalltalk es grande, y hasta en nombres de la biblioteca estándar queda esa huella, con cosas como collect en vez de map. En Ruby, de principio a fin, todo es un objeto, y lo natural es entender las llamadas a métodos como enviar mensajes a objetos. Se compara mucho con Python, pero su ruta evolutiva fue bastante distinta, y ahora da la impresión de que convergieron hacia ecosistemas parecidos. Para mí, Ruby se siente como una alpaca más acogedora que Python

    • Python también puede verse en la práctica como un lenguaje puramente OOP desde las new style classes. A nivel Hello World se nota menos, pero incluso los tipos básicos pasaron a ser objetos. Si quieres remarcarle eso a alguien que no soporta OOP, basta mostrarle type(42) y dir(42) para dejar claro que hasta un entero es un objeto
    • Siento que señalar un solo lenguaje prototipo como lenguaje orientado a objetos en realidad confunde más a la gente. OO se parece más a un estilo de programación, como lo procedimental, y no creo que tenga mucho sentido meter a Python y C++ en la misma categoría solo porque ambos tienen herencia múltiple
    • Ya que salió la analogía del camello, me quedé pensando si camel no era originalmente más bien un símbolo de Perl
  • Yo añadiría una categoría más al árbol genealógico de lenguajes: los lenguajes para expresar pruebas. Son los de la correspondencia Curry-Howard, donde el programa es la prueba, y Lean sería un ejemplo representativo. Podría verse como una subcategoría de lo funcional, pero siento que vale la pena tratarlo como otro eje, porque su objetivo principal es la verificación más que la ejecución

    • A mí me parece que la demostración de teoremas y los tipos complejos son más bien extensiones montadas sobre lenguajes ya existentes. Agda e Idris son funcionales con tipos complejos añadidos, e Isabelle y Lean son eso más prueba interactiva. Dafny va más por el lado imperativo con teoremas y pistas encima, y ACL2 se entiende fácil si lo ves como un Lisp con theorem/hint. Además, como se ve en los traits de Rust, los typeclasses se sienten como una especie de programación lógica que corre sobre lenguajes funcionales e imperativos
    • Por definición, esta clase de lenguajes no tiene completitud de Turing, así que me cuesta verlos como lenguajes de programación de verdad. Si fueran Turing completos, podrías fabricar pruebas falsas con programas que nunca terminan
    • Yo veo esta familia como un flujo derivado directamente de ML al final de cuentas
    • Lean claramente es un lenguaje dependently typed de la familia ML, cercano a Agda e Idris, así que en grande sí puede ir dentro de la clasificación ML. Y tampoco me parece que el objetivo de largo plazo de Lean sea que la ejecución sea algo secundario. Microsoft sí está interesado en escribir software real. En cambio, si enfatizas más lo de “lenguaje para expresar pruebas”, entonces tampoco se puede dejar fuera a Prolog, así que podrías ver a Lean como mitad ML y mitad Prolog. Desde esa perspectiva, la correspondencia Curry-Howard se siente como una forma de implementar lógica computacional
  • Hace poco volví a revisar un proyecto de comparación de lenguajes: era un benchmark que descomponía cíclicamente en paralelo las 3,715,891,200 signed permutations de 10 caracteres. Más que “lenguajes prototipo”, quería encontrar implementaciones modernas de cada paradigma que de verdad se pudieran elegir para programación de investigación. No solo miré rendimiento, también qué tan fácil era recibir ayuda de IA y qué tan cómodo me resultaba leer y pensar el código; gracias a la IA, además, se pudo hacer una especie de turismo optimizando cada lenguaje con bastante profundidad. Los resultados están aquí, y en particular me sorprendió mucho que F# quedara hasta arriba

    • A primera vista suena inesperado, pero creo que los detalles son lo importante. Si sacas a Lean, en general las diferencias numéricas no son tan dramáticas, y que Chez sea 2.5 veces más lento que C++ tampoco está nada mal para un lenguaje JIT dinámico. Que F# sea fuerte en este tipo de trabajo probablemente tiene mucho que ver con que la experiencia de paralelismo sobre .NET Core está especialmente madura y bien resuelta. Si ese número es elapsed time, sería todavía más interesante ver también el desglose de CPU time. Además, la estrategia de paralelización cambia un poco según el lenguaje, así que no es una comparación bajo condiciones totalmente idénticas. Por ejemplo, la simple bifurcación por hilos en F# y el iterador paralelo de Rayon en Rust pueden tener estructuras de overhead distintas. Al final, Rust y C++ quizá podrían ir más rápido si se trabajaran con cuidado las primitivas de concurrencia de bajo nivel del SO, pero eso ya sería otro tipo de comparación. También es ambiguo si habría que permitir el uso de C FFI desde C o Haskell, así que este tipo de comparaciones inevitablemente mezclan mucho juicio cualitativo. Por cierto, el código de Chez quizá podría acelerarse si guardara las permutations en fxvector y usara operaciones especializadas para fixnum, reduciendo boxing/unboxing y asignaciones. La documentación relevante está en la documentación de objetos de Chez Scheme
  • Yo también escribí algo parecido aquí. Coincido con Algol, Lisp, Forth, APL y Prolog, pero para lenguaje funcional innovador puse SASL, que es un poco anterior a ML, y como representante orientado a objetos elegí Smalltalk, que salió antes que Self. Además incluí Fortran, COBOL, SNOBOL y Prograph, porque me parecen lenguajes que cada uno cambió el panorama a su manera

    • Esta lista me gusta más. Sobre todo me alegra ver SNOBOL ahí. Nunca lo usé, pero fue uno de los primeros lenguajes de los que supe porque de niño vi un libro suyo en una venta de libros de biblioteca pública y el nombre me pareció divertido. Antes de eso solo conocía BASIC, Logo y un poco de ensamblador 6502, apenas lo suficiente como para llamarlo desde BASIC siguiendo ejemplos del manual de Atari BASIC. También me cuesta imaginar una lista de lenguajes innovadores sin Fortran y COBOL, o incluso sin su raíz, FLOW-MATIC. El libro que tomé como referencia era el manual de Atari BASIC
    • No entiendo bien por qué no entró Smalltalk en lugar de Self. Smalltalk fue anterior, y además Alan Kay fue quien acuñó el propio término “OOP”. Yo también tiendo a ver a ML, por su genealogía, como hijo de Lisp
  • Yo añadiría a esta discusión más familias semánticas. Cosas como Verilog, Petri nets, Kahn process networks, dataflow machines, process calculi, reactive, term rewriting, constraint solver/theorem prover, y probabilistic programming. También pienso en lenguajes como Unison, Darklang, temporal dataflow y DBSP, que no encajan exactamente en esas 7 categorías pero en la práctica están cerca de producción. Puede parecer un poco tramposo, pero en esencia se trata de modelos de cómputo paralelos al modelo de máquina de von Neumann. Desde hace tiempo me gustaría escribir algo como “todas las formas de computación que conocemos, más allá de von Neumann”

    • Si saliera un texto así, lo leería con muchísimo gusto. Mientras tanto, me hizo recordar parte de un texto de Steve Yegge. La idea central era que buena parte de la educación moderna en CS en realidad está construida sobre el marco creado por von Neumann, y que elegir dispositivos secuenciales también fue una decisión marcada por la realidad de costos y velocidad de fabricación de la época. También me impresionó la parte sobre cómo muchos elementos que aprendemos —arquitectura de máquinas, branching, loops, subrutinas, depuración, conversión de sistemas numéricos, modelado de problemas— ya estaban en su trabajo. La cita relacionada está en este archive
    • Lo de term rewriting me hizo recordar cuando en la universidad me tocó el parser de fórmulas de un software de hoja de cálculo. Me atoré toda una semana, hasta que al final entendí que si reescribía 1+1 como algo tipo ADD(1,1), ya podía parsearlo de una forma que sí entendía. Encima me negué tontamente a aprender regex, así que el código quedó bastante raro, y todavía me acuerdo de un compañero diciendo “como Andy dice que funciona, mejor no lo toquemos”. Gente de otro equipo resolvió lo mismo con regex en un código como 20 veces más corto que el mío
    • Sobre lo de “lenguajes emergentes listos para producción”, yo metería también en una categoría parecida sistemas como ChatGPT, aunque para mí todavía no estén del todo listos para producción completa. Es discutible si eso cuenta o no como lenguaje de programación, pero sí me parece defendible porque es un medio por el cual una persona le dice a una computadora qué hacer. Y no creo que ser no determinista descalifique automáticamente a algo como lenguaje de programación
    • También creo que el texto de Sussman sobre propagators vale mucho la pena
    • Como ejemplo de logic programming en S9 Scheme, este material estaba bastante bien. Ni siquiera hace falta comprar el libro para bajar el código de una vez, y si primero agarras lo básico con un texto introductorio como Simply Scheme, luego la estructura del solver se deja leer bastante fácil
  • “Concepts of programming languages”, que tomé en TU Delft, fue mi materia favorita de toda la carrera de computación. Vimos C, Scala del lado funcional, y JavaScript por el concepto de prototipos, y gracias a eso años después aprender Elixir me resultó mucho más fácil. También había una clase donde programábamos agentes de Unreal Tournament en GOAL, un lenguaje basado en Prolog. Durante mucho tiempo no supe bien dónde usar Prolog, pero al final lo terminé usando para hacer un spellcheck que corrigiera iterativamente frases pésimas en papiamento generadas por un LLM

    • Yo tomé una clase parecida, y aunque el profesor no era gran cosa, sí siento que valió muchísimo la pena. Tan solo conocer aunque sea muy superficialmente los otros lenguajes prototipo ya te amplía la perspectiva, y si además sumas ensamblador el efecto es todavía mayor. Aunque nunca los uses para producir algo directamente, al menos evitas la trampa de andar con un martillo y ver todos los problemas como clavos
    • Yo también estuve en esa clase. Lo de Unreal Tournament fue de las materias más geniales que vi, y según recuerdo desapareció al año siguiente. Me da algo de lástima que ahora parezca haberse vuelto una clase de IA más del montón, como las que da todo el mundo. Yo sigo sin encontrarle tantos usos claros a Prolog, pero GOAL sí me dejó una impresión mucho más fuerte. Y solo recientemente me di cuenta, con algo de decepción, de que esa estructura se puede recrear también en lenguajes más “normales”, con bastantes ventajas además
    • Me preguntaba si el GOAL del que hablas es Game Oriented Assembly Lisp
  • Estoy de acuerdo con la idea de que hay que aprender lenguajes de clases distintas. No fue hasta que aprendí OCaml que las funciones empezaron a sentirse de verdad como funciones matemáticas, y Mathematica me enseñó a ver las expresiones mismas como entradas. La notación polaca inversa de PostScript no solo me sirvió para aritmética simple: literalmente me recableó la forma de pensar. Pero no estoy de acuerdo con decir que da igual elegir entre Java, C#, C++, Python o Ruby. Si tu meta es algo como implementar quicksort, quizá sí se parezcan, pero para alguien que realmente quiere construir cosas, la elección del lenguaje puede marcar una diferencia tan grande como de día y noche. Si a alguien que quiere hacer juegos 3D le das Ruby, o a alguien que quiere hacer ciencia de datos exploratoria o deep learning le das Java como primer lenguaje, puedes matarle la motivación

    • Yo probablemente nunca gane dinero con Rust, pero no me arrepiento nada de haberlo aprendido. Rust realmente te obliga a pensar muy a fondo en la propiedad de los datos dentro de un programa
  • Este artículo me hizo pensar en 7 languages in 7 weeks de Bruce Tate. Yo también conocí Erlang por ese libro. Aun así, históricamente me parece un poco forzado meter a COBOL y Fortran dentro de la familia Algol, aunque al mismo tiempo sí recuerda que la historia inevitablemente tiene algo de simplificación reductiva

    • Incluso irse más atrás para fijar una clasificación primitiva me parece forzado. Los primeros lenguajes assembly también eran imperativos, pero lo que hizo interesantes a Algol, Fortran y Cobol fue que permitieron programación compleja gracias a funciones y otras capacidades de alto nivel. Algol fue el que dejó más descendientes, pero yo diría que el primer lenguaje de programación imperativo fue Fortran
    • Solo viendo Wikipedia, pareciera que Fortran y Algol se desarrollaron ambos alrededor de 1957, pero me dio curiosidad cuál salió realmente primero y si durante el diseño hubo influencia mutua o traslape entre ambos
    • Más bien pensaría en COBOL como un fósil viviente. Y el Fortran actual me da la impresión de ser un lenguaje basado en la familia FORTRAN que luego recibió por transferencia horizontal varios rasgos del linaje Algol
  • Relacionado con esto, ya hubo una discusión vieja en HN. Ver la discusión anterior también ayuda a entender el contexto

    • Para ser exactos, fue la discusión del 4 de mayo de 2023 y tuvo 323 comentarios. Y una todavía más antigua fue este hilo del 30 de septiembre de 2021, que tuvo 29 comentarios