Explora cómo el enfoque simbólico de John McCarthy y las ideas de diseño de Lisp—listas, recursión y recolección de basura—influyeron en la IA y la programación moderna.

Esto no es un tour de museo de la “IA antigua”. Es una lección histórica práctica para cualquiera que construya software—programadores, leads técnicos y responsables de producto—porque las ideas de John McCarthy moldearon cómo pensamos sobre para qué sirven los lenguajes de programación.
Lisp no fue solo una nueva sintaxis. Fue una apuesta de que el software podría manipular ideas (no solo números) y que las decisiones de diseño del lenguaje podían acelerar la investigación, la iteración de producto y ecosistemas de herramientas enteros.
Una forma útil de leer el legado de McCarthy es verlo como una pregunta que aún importa hoy: ¿qué tan directamente podemos convertir la intención en un sistema ejecutable—sin ahogarnos en boilerplate, fricción o complejidad accidental? Esa pregunta resuena desde el REPL de Lisp hasta los flujos modernos de “chat-a-aplicación”.
John McCarthy no solo se recuerda por ayudar a lanzar la IA como campo de investigación, sino por insistir en un tipo específico de IA: sistemas que pudieran manipular ideas, no meramente calcular respuestas. A mediados de los años 50 organizó el Dartmouth Summer Research Project (donde se propuso el término “inteligencia artificial”) y luego influyó el trabajo en IA en MIT y después en Stanford. Pero su contribución más duradera quizá sea la pregunta que no dejaba de plantear: ¿y si el razonamiento mismo pudiera expresarse como un programa?
La mayoría de los primeros éxitos informáticos fueron numéricos: tablas balísticas, simulaciones de ingeniería, optimización y estadística. Esos problemas encajaban bien en la aritmética.
McCarthy apuntó a algo distinto. El razonamiento humano opera a menudo con conceptos como “si”, “porque”, “pertenece a”, “es un tipo de” y “todas las cosas que cumplen estas condiciones”. Eso no se representa de forma natural con valores de punto flotante.
El enfoque de McCarthy trataba el conocimiento como símbolos (nombres, relaciones, categorías) y concebía el pensamiento como transformaciones basadas en reglas sobre esos símbolos.
Una forma de verlo a alto nivel: los enfoques numéricos responden “¿cuánto?” mientras que los simbólicos intentan responder “¿qué es?” y “¿qué se sigue de lo que sabemos?”.
Si crees que el razonamiento puede hacerse programable, necesitas un lenguaje que pueda representar cómodamente expresiones como reglas, afirmaciones lógicas y relaciones anidadas—y luego procesarlas.
Lisp se construyó para ese objetivo. En lugar de forzar las ideas en estructuras de datos rígidas y predefinidas, Lisp hacía natural representar código y conocimiento con formas similares. Esa elección no fue solo estilística: fue un puente práctico entre describir un pensamiento y ejecutar un procedimiento, que es exactamente el cruce que McCarthy quería para la IA.
Cuando McCarthy y los primeros investigadores en IA decían “simbólico”, no hablaban de matemáticas misteriosas. Un símbolo es simplemente una etiqueta con significado: un nombre como customer, una palabra como hungry, o una marca como IF y THEN. Los símbolos importan porque permiten a un programa trabajar con ideas (categorías, relaciones, reglas) en vez de solo números brutos.
Una forma sencilla de imaginarlo: las hojas de cálculo son geniales cuando tu mundo son columnas y operaciones aritméticas. Los sistemas simbólicos son geniales cuando tu mundo son reglas, categorías, excepciones y estructura.
En muchos programas, la diferencia entre 42 y "edad" no es el tipo de dato—es lo que el valor representa. Un símbolo te da algo con lo que comparar, almacenar y combinar sin perder significado.
Eso hace natural representar cosas como “París es una ciudad” o “si la batería está baja, busca un cargador”.
Para hacer algo útil con símbolos necesitas estructura. Lisp popularizó una estructura muy simple: la lista. Una lista es simplemente un grupo ordenado de elementos, y esos elementos pueden ser listas a su vez. Con esa única idea puedes representar oraciones, formularios y conocimiento con forma de árbol.
Aquí hay un ejemplo conceptual pequeño (en estilo Lisp):
(sentence (subject robot) (verb needs) (object power))
Se lee casi como inglés: una oración compuesta por sujeto, verbo y objeto. Como está estructurada, un programa puede extraer (subject robot) o reemplazar (object power) por otra cosa.
Una vez que la información está en estructuras simbólicas, las tareas clásicas de IA se vuelven abordables:
IF un patrón coincide, THEN concluye algo nuevo.El cambio clave es que el programa no solo calcula; manipula piezas de conocimiento significativas en una forma que puede inspeccionar y transformar.
Las decisiones de diseño de Lisp no se quedaron en la academia. Influyeron en cómo la gente construyó herramientas y en la rapidez con que podían explorar ideas:
Esas cualidades tienden a producir ecosistemas donde experimentar es barato, los prototipos se convierten en productos más rápido y los equipos pueden adaptarse cuando cambian los requisitos.
Lisp nació con un problema de diseño muy práctico: ¿cómo escribir programas que trabajen con símbolos tan naturalmente como trabajan con números?
McCarthy no intentaba crear una “mejor calculadora”. Quería un lenguaje donde una expresión como (is (parent Alice Bob)) pudiera almacenarse, inspeccionarse, transformarse y razonarse tan fácilmente como (+ 2 3).
La prioridad fue hacer que la información simbólica fuera fácil de representar y manipular. Eso llevó a enfocarse en listas y estructuras tipo árbol, porque encajan bien con formas que los humanos ya usan para expresar significado: oraciones, reglas lógicas, categorías anidadas y relaciones.
Otro objetivo fue mantener el núcleo del lenguaje pequeño y consistente. Cuando un lenguaje tiene menos “casos especiales”, pasas menos tiempo memorizando reglas y más tiempo componiendo ideas. Lisp se inclinó por un pequeño conjunto de bloques que podían combinarse en abstracciones mayores.
Una idea clave fue que los programas y los datos pueden compartir la misma estructura. En pocas palabras: si tus datos son una lista anidada, tu programa puede ser también una lista anidada.
Eso significa que puedes:
Lisp también popularizó una mentalidad: los lenguajes no tienen que ser talla única. Pueden diseñarse alrededor de un dominio—como razonamiento, búsqueda y representación del conocimiento—y aun así influir en la programación general durante décadas.
Las S-expressions (expresiones simbólicas) son la idea distintiva de Lisp: una forma única y consistente de representar código y datos como listas anidadas.
A simple vista, una S-expression es solo paréntesis alrededor de ítems—algunos ítems son átomos (nombres y números), y otros son listas. La regla de “listas dentro de listas” es todo el propósito.
Como la estructura es uniforme, los programas Lisp se construyen con los mismos bloques desde abajo hacia arriba. Una llamada a función, un fragmento de configuración y una pieza de la estructura del programa pueden expresarse como una lista.
Esa consistencia paga de inmediato:
Incluso si nunca escribes en Lisp, ésta es una lección de diseño importante: cuando un sistema se construye a partir de una o dos formas previsibles, pasas menos tiempo luchando con casos límite y más tiempo construyendo.
Las S-expressions fomentan la composición porque piezas pequeñas y legibles se combinan naturalmente en otras mayores. Cuando tu programa es “solo listas anidadas”, combinar ideas suele implicar anidar una expresión dentro de otra o ensamblar listas a partir de partes reutilizables.
Esto te empuja hacia un estilo modular: escribes operaciones pequeñas que hacen una cosa y luego las apilas para expresar una intención mayor.
El inconveniente obvio es la falta de familiaridad. Para muchos recién llegados, una sintaxis cargada de paréntesis parece extraña.
Pero la ventaja es la previsibilidad: una vez entiendes las reglas de anidación puedes ver la estructura de un programa de forma fiable—y las herramientas también. Esa claridad es una gran razón por la que las S-expressions tuvieron consecuencias más allá de Lisp.
La recursión se entiende mejor con una metáfora cotidiana: ordenar una habitación desordenada haciendo habitaciones más pequeñas. No intentas resolver todo a la vez. Recoges un objeto, lo pones donde corresponde y repites la misma acción con lo que queda. Los pasos son simples; el poder viene de repetirlos hasta que no quede nada por hacer.
Lisp apuesta por esta idea porque gran parte de sus datos se construye naturalmente a partir de listas: una lista tiene una “primera cosa” y “el resto”. Esa forma encaja perfectamente con el pensamiento recursivo.
Para procesar una lista, manejas el primer elemento y luego aplicas la misma lógica al resto. Cuando la lista está vacía, paras—ese es el limpio momento de “no queda nada por hacer” que hace que la recursión parezca bien definida en vez de misteriosa.
Imagina que quieres el total de una lista de números.
Eso es todo. La definición se lee como lenguaje natural y la estructura del programa refleja la idea.
La IA simbólica suele representar expresiones como estructuras en árbol (un operador con subexpresiones). La recursión es una forma natural de “recorrer” ese árbol: evalúa la parte izquierda como evalúas la derecha y sigue hasta llegar a un valor simple.
Estos patrones ayudaron a moldear la programación funcional posterior: funciones pequeñas, casos base claros y transformaciones de datos fáciles de razonar. Incluso fuera de Lisp, el hábito de dividir el trabajo en “haz un paso, luego repite sobre el resto” conduce a programas más limpios y menos efectos secundarios ocultos.
Los primeros programadores a menudo tenían que gestionar la memoria a mano: asignar espacio, seguir quién lo “posee” y recordar liberarlo en el momento adecuado. Ese trabajo no solo ralentiza el desarrollo: crea una clase de errores difícil de reproducir y fácil de enviar a producción: fugas que degradan el rendimiento y punteros colgantes que hacen fallar programas mucho después del error original.
John McCarthy introdujo la recolección de basura para Lisp como una forma de permitir que los programadores se centraran en el significado en lugar de la contabilidad.
A alto nivel, la recolección de basura (GC) encuentra automáticamente piezas de memoria que ya no son accesibles desde el programa en ejecución—valores que nadie puede usar nunca más—y recupera ese espacio.
En vez de preguntar “¿liberamos cada objeto exactamente una vez?”, la GC cambia la pregunta a “¿este objeto sigue siendo accesible?”. Si el programa no puede alcanzarlo, se considera basura.
Para el trabajo de IA simbólica, los programas Lisp crean con frecuencia muchas listas, árboles y resultados intermedios de corta vida. La gestión manual de memoria convertiría la experimentación en una batalla constante con la limpieza de recursos.
La GC cambia la experiencia diaria:
La idea clave es que una característica del lenguaje puede ser un multiplicador de equipo: menos horas depurando corrupción misteriosa significa más tiempo mejorando la lógica real.
La decisión de McCarthy no se quedó en Lisp. Muchos sistemas posteriores adoptaron GC (y sus variantes) porque el trade-off suele compensar: Java, C#, Python, entornos de JavaScript y Go dependen de la recolección de basura para hacer el desarrollo a gran escala más seguro y rápido—incluso cuando el rendimiento importa.
En Lisp, una expresión es un trozo de código escrito en una forma consistente (a menudo una lista). Evaluar es simplemente el proceso de decidir qué significa esa expresión y qué produce.
Por ejemplo, cuando escribes algo como “sumar estos números” o “llamar a esta función con estos inputs”, el evaluador sigue un pequeño conjunto de reglas para convertir esa expresión en un resultado. Piénsalo como el árbitro del lenguaje: decide qué hacer después, en qué orden y cuándo parar.
El movimiento clave de McCarthy no fue solo inventar nueva sintaxis—fue mantener el “motor de significado” compacto y regular. Cuando el evaluador se construye con pocas reglas claras, suceden dos cosas buenas:
Esa consistencia es una de las razones por las que Lisp se convirtió en un terreno de pruebas para ideas en IA simbólica: los investigadores podían probar nuevas representaciones y estructuras de control rápidamente, sin esperar a que un equipo de compilador rediseñara el lenguaje.
Las macros son la forma en que Lisp te permite automatizar formas de estructura de código repetitivas, no solo valores repetidos. Donde una función evita repetir cálculos, una macro evita repetir estructuras comunes—como “haz X, pero también regístralo” o “define un mini-lenguaje para reglas”.
El efecto práctico es que Lisp puede crecer nuevas comodidades desde dentro. Muchas herramientas modernas hacen eco de esta idea: sistemas de plantillas, generadores de código y características de metaprogramación, porque sirven al mismo objetivo: experimento más rápido e intención más clara.
Si tienes curiosidad por cómo esta mentalidad influyó en flujos de desarrollo cotidianos, ve a /blog/the-repl-and-fast-feedback-loops.
Una gran parte del atractivo de Lisp no fue solo el lenguaje: fue cómo se trabajaba con él. Lisp popularizó el REPL: Read–Eval–Print Loop. En términos cotidianos, es como tener una conversación con el ordenador. Escribes una expresión, el sistema la ejecuta inmediatamente, imprime el resultado y espera tu siguiente entrada.
En lugar de escribir un programa completo, compilarlo, ejecutarlo y luego buscar qué falló, puedes probar ideas paso a paso. Puedes definir una función, probarla con algunos inputs, ajustarla y probar de nuevo—todo en segundos.
Ese ritmo fomenta la experimentación, lo cual importó mucho en la IA temprana donde a menudo no sabías cuál era el enfoque correcto desde el inicio.
La retroalimentación rápida convierte “apuestas grandes” en “chequeos pequeños”. Para la investigación, facilita explorar hipótesis e inspeccionar resultados intermedios.
Para la creación de productos, reduce el coste de iteración: puedes validar comportamientos con datos reales rápidamente, notar los casos límite antes y refinar funciones sin esperar largos ciclos de compilación.
Esto es también por qué las herramientas modernas de vibe-coding resultan atractivas: son esencialmente una compresión agresiva del bucle de retroalimentación. Por ejemplo, Koder.ai usa una interfaz de chat (con una arquitectura basada en agentes debajo) para convertir la intención de producto en código web, backend o móvil funcional rápidamente—a menudo haciendo que el bucle “probar → ajustar → probar otra vez” se parezca más a un REPL que a una tubería tradicional.
La idea del REPL aparece hoy en:
Diferentes herramientas, mismo principio: acortar la distancia entre pensar y ver.
Los equipos se benefician más de flujos tipo REPL cuando exploran requisitos inciertos, construyen características con muchos datos, diseñan APIs o depuran lógica compleja. Si el trabajo implica aprendizaje rápido—sobre usuarios, datos o casos límite—la retroalimentación interactiva no es un lujo; es un multiplicador.
Lisp no “ganó” convirtiéndose en la sintaxis de todos los días. Ganó sembrando ideas que se volvieron normales en muchos ecosistemas.
Conceptos que Lisp trataba por defecto—funciones como valores, uso intensivo de operaciones de orden superior y preferencia por componer partes pequeñas—aparecen hoy por doquier. Incluso lenguajes que no se parecen a Lisp fomentan transformaciones con map/filter, hábitos de datos inmutables y pensamiento recursivo (a menudo expresado con iteradores o folds).
El cambio clave es mental: trata las transformaciones de datos como pipelines y el comportamiento como algo que puedes pasar alrededor.
Lisp facilitó representar programas como datos. Esa mentalidad aparece hoy en cómo construimos y manipulamos ASTs (árboles de sintaxis abstracta) para compiladores, formateadores, linters y generadores de código. Cuando trabajas con un AST, haces un primo cercano de “código como datos”, aunque las estructuras sean objetos JSON, nodos tipados o grafos de bytecode.
El mismo enfoque simbólico impulsa la automatización práctica: formatos de configuración, sistemas de plantillas y pipelines de construcción dependen de representaciones estructuradas que las herramientas pueden inspeccionar, transformar y validar.
Los lenguajes familiares a la familia Lisp (en sentido amplio: Lisps contemporáneos e inspirados en Lisp) siguen influyendo en cómo los equipos diseñan DSLs internas: pequeños mini-lenguajes enfocados para tests, despliegue, procesamiento de datos o UI.
Fuera de Lisp, sistemas de macros, bibliotecas de metaprogramación y frameworks de generación de código buscan el mismo resultado: extender el lenguaje para ajustarlo al problema.
Una conclusión pragmática: las preferencias sintácticas cambian, pero las ideas duraderas—estructura simbólica, funciones componibles y extensibilidad—siguen rindiendo frutos a través de décadas y bases de código.
Lisp tiene una reputación que oscila entre “brillante” e “ilegible”, a menudo basada en impresiones de segunda mano más que en la experiencia diaria. La verdad es más ordinaria: Lisp toma decisiones potentes en el contexto adecuado y poco prácticas en otros.
Para los recién llegados, la sintaxis uniforme de Lisp puede sentirse como ver el “interior” de un programa en lugar de su superficie pulida. Esa incomodidad es real, especialmente si vienes de lenguajes donde la sintaxis separa visualmente las construcciones.
Históricamente, sin embargo, la estructura de Lisp es también la intención: código y datos comparten la misma forma, lo que facilita transformar, generar y analizar programas. Con buen soporte de editor (indentado, navegación estructural), el código Lisp a menudo se lee por su forma más que por contar paréntesis.
Un estereotipo común es que Lisp es inherentemente lento. Históricamente, algunas implementaciones sí tuvieron dificultades frente a lenguajes de bajo nivel, y las características dinámicas pueden añadir sobrecarga.
Pero no es exacto tratar “Lisp” como un único perfil de rendimiento. Muchas implementaciones de Lisp han soportado compilación, declaraciones de tipo y optimización seria. La forma más útil de plantearlo es: ¿cuánto control necesitas sobre el layout de memoria, latencias previsibles o rendimiento crudo?—y ¿tu implementación de Lisp apunta a esas necesidades?
Otra crítica válida es el encaje en el ecosistema. Dependiendo del dialecto y el dominio, librerías, herramientas y pools de talento pueden ser más pequeños que los stacks mainstream. Eso puede importar más que la elegancia del lenguaje si necesitas lanzar rápido con un equipo amplio.
En vez de juzgar Lisp por sus estereotipos, evalúa sus ideas subyacentes independientemente: estructura uniforme, desarrollo interactivo y macros como herramienta para construir abstracciones de dominio. Incluso si nunca despliegas un sistema Lisp, esos conceptos pueden afilar cómo piensas sobre diseño de lenguajes y cómo escribes código en cualquier lenguaje.
McCarthy no solo nos dejó un lenguaje histórico—nos dejó un conjunto de hábitos que todavía hacen el software más fácil de cambiar, explicar y extender.
Prefiere núcleos simples sobre superficies inteligentes. Un pequeño conjunto de bloques ortogonales es más fácil de aprender y más difícil de romper.
Mantén formas de datos uniformes. Cuando muchas cosas comparten la misma representación (como listas/árboles), las herramientas se simplifican: impresoras, depuradores, serializadores y transformadores se pueden reutilizar.
Trata los programas como datos (y los datos como programas) cuando convenga. Si puedes inspeccionar y transformar estructuras, puedes construir refactors, migraciones y generadores de código más seguros.
Automatiza lo aburrido. La recolección de basura es el ejemplo clásico, pero el punto es más amplio: invierte en automatización que prevenga clases enteras de errores.
Optimiza los bucles de retroalimentación. La evaluación interactiva (estilo REPL) fomenta pequeños experimentos, verificación rápida y mejor intuición sobre el comportamiento.
Haz que la extensión sea un objetivo de diseño de primera clase. Las macros de Lisp son una respuesta; en otros ecosistemas pueden ser plugins, plantillas, DSLs o transformaciones en tiempo de compilación.
Antes de elegir una librería o arquitectura, toma una función real—por ejemplo “reglas de descuento” o “enrutamiento de tickets”—y dibújala como árbol. Luego reescribe ese árbol como listas anidadas (o JSON). Pregúntate: ¿cuáles son los nodos, cuáles las hojas y qué transformaciones necesitas?
Aunque no uses Lisp, puedes adoptar la mentalidad: construye representaciones estilo AST, usa generación de código para el pegamento repetitivo y estandariza en pipelines orientados a datos (parsear → transformar → evaluar). Muchos equipos obtienen los beneficios simplemente haciendo explícitas las representaciones intermedias.
Si te gusta el principio REPL pero entregas funciones de producto en stacks mainstream, también puedes tomar el espíritu en las herramientas: ciclos de iteración cortos, snapshots/rollback y planificación explícita antes de ejecutar. Koder.ai, por ejemplo, incluye un modo de planificación además de snapshots y rollback para mantener la iteración rápida más segura—un eco operacional del “cambia rápido, pero mantén el control” de Lisp.
La influencia duradera de McCarthy es esta: programar se vuelve más poderoso cuando hacemos programable el razonamiento mismo—y mantenemos el camino de la idea al sistema ejecutable lo más directo posible.
El pensamiento simbólico representa conceptos y relaciones directamente (p. ej., “cliente”, “es-un”, “depende-de”, “si…entonces…”), y luego aplica reglas y transformaciones a esas representaciones.
Es más útil cuando tu problema está lleno de estructura, excepciones y significado (motores de reglas, planificación, compiladores, configuración, lógica de flujos de trabajo), no solo aritmética.
McCarthy impulsó la idea de que el razonamiento puede expresarse como programas, no solo como cálculos.
Esa perspectiva dio forma a:
Las listas son una forma mínima y flexible de representar “cosas hechas de partes”. Como los elementos de una lista pueden ser listas a su vez, obtienes naturalmente estructuras en árbol.
Eso facilita:
Las S-expressions te dan una forma única y uniforme para código y datos: listas anidadas.
Esa uniformidad suele simplificar sistemas porque:
Un macro automatiza estructuras de código repetitivas, no solo cálculos repetidos.
Usa macros cuando quieras:
Si solo necesitas lógica reutilizable, normalmente una función es la opción adecuada.
La recolección de basura (GC) recupera automáticamente la memoria que ya no es accesible, lo que reduce categorías enteras de errores (punteros colgantes, liberaciones dobles).
Es especialmente útil cuando tu programa crea muchas estructuras de corta vida (listas/árboles/ASTs), porque puedes prototipar y refactorizar sin diseñar un esquema manual de propiedad de memoria desde el inicio.
Un REPL acorta el ciclo “pensar → probar → observar”. Puedes definir una función, ejecutarla, ajustarla y volver a probar inmediatamente.
Para conseguir el mismo beneficio en stacks no-Lisp:
Lectura relacionada: /blog/the-repl-and-fast-feedback-loops
Muchas prácticas modernas reutilizan las mismas ideas subyacentes:
map/filter, composición)Aunque nunca metas Lisp en producción, probablemente ya uses hábitos heredados de Lisp a diario.
Trade-offs reales:
En la práctica, evalúa el encaje por dominio y restricciones, no por reputación.
Prueba este ejercicio de 10 minutos:
Esto suele revelar dónde patrones de “código-como-datos”, motores de reglas o configuraciones tipo DSL simplifican el sistema.