Lenguajes formales: cómo se expresa la lógica sin ambigüedad
Si programar nace en la lógica (la idea) y hoy un agente de IA puede encargarse de codificarla, ¿por qué sigue siendo necesario traducir esa idea a un lenguaje formal de programación en lugar de que el servidor ejecute frases en español? Porque los idiomas humanos están diseñados para ser flexibles y depender del contexto implícito, mientras que una máquina necesita un medio de expresión formal libre de ambigüedad.
Objetivos y conocimientos previos
Partiendo de Recursos de ejecución, comprenderás la relación entre la lógica (donde nace el programa) y el lenguaje formal (la manera de expresarla), cuáles son las cinco piezas universales que comparten todos los lenguajes de programación más allá de su sintaxis, y por qué los sistemas de tipos son uno de tus mejores aliados para verificar el código que genera un agente.
Lenguaje natural (el encargo) frente a lenguaje formal (el código)
Observa esta frase perfectamente normal en español:
«Aplica un descuento a los clientes antiguos o con suscripción anual y factura mayor de 100 €».
Para una persona parece clara, pero admite dos interpretaciones lógicas distintas:
(cliente_antiguo O suscripcion_anual) Y (factura > 100)→ la factura debe superar 100 € en ambos casos.cliente_antiguo O (suscripcion_anual Y factura > 100)→ al cliente antiguo se le aplica el descuento aunque su factura sea de 10 €.
| Característica | Lenguaje Natural (Español, Inglés — tu prompt) | Lenguaje Formal (Código de programación) |
|---|---|---|
| Ambigüedad | Alta: una misma frase admite varias lecturas según lo que se dé por sentado. | Nula: cada expresión tiene una única interpretación definida por la gramática y precedencia del lenguaje. |
| Tolerancia a omisiones | Alta: un humano rellena huecos con sentido común (o con suposiciones propias). | Ninguna: si no se especifica qué ocurre cuando un valor no existe, el proceso falla o sigue la rama literal escrita. |
| Función en el desarrollo con IA | Explorar el problema, explicar el contexto, negociar opciones y formular especificaciones. | Fijar de manera determinista, auditable y repetible el comportamiento exacto del sistema. |
Por eso el prompt nunca sustituye a la lógica formal: cuando das una instrucción ambigua en lenguaje natural, el agente elige una interpretación concreta al escribir el código formal. Si no sabes qué expresa ese código formal, no sabrás qué decisión tomó por ti.
Los cinco bloques universales de cualquier lenguaje de programación
Existen decenas de lenguajes de programación porque cada uno prioriza distintos compromisos (control directo de memoria, rapidez de desarrollo, seguridad de tipos o concurrencia). Sin embargo, todos expresan la lógica combinando las mismas cinco construcciones:
| Construcción universal | Qué papel cumple en el modelo lógico | Qué debes vigilar cuando lo escribe un agente |
|---|---|---|
| 1. Nombres, valores y ámbito (Variables y Constantes) | Asignan un nombre simbólico a un dato en memoria dentro de un alcance (ámbito) determinado. | Que los valores que no deben cambiar sean inmutables (constantes) y que un dato no sea modificado por accidente desde otra parte del programa. |
| 2. Tipos y estructuras de datos | Definen qué clase de valores admite cada nombre y cómo se agrupan (registros, listas, diccionarios/mapas, conjuntos). | Que los tipos reflejen las restricciones del dominio (por ejemplo, que no se permita un valor vacío/nulo donde la regla exige siempre un identificador válido). |
| 3. Expresiones y control de flujo | Evalúan condiciones lógicas (Y, O, NO, comparaciones) para decidir ramas y repetir operaciones sobre colecciones con condición de parada. | Que todas las ramas posibles estén cubiertas (incluido el caso vacío o de error) y que ninguna repetición pueda quedar atrapada sin terminar. |
| 4. Funciones (Abstracción de procesos) | Encapsulan una transformación con un nombre, parámetros de entrada definidos y un resultado de salida. | Distinguir funciones puras (solo calculan un resultado a partir de sus entradas, sin tocar nada más: muy fáciles de probar) de funciones con efectos secundarios (modifican la base de datos o llaman a la red). |
| 5. Módulos y paquetes | Agrupan funciones y tipos relacionados en unidades independientes con una interfaz pública explícita. | Que respeten la separación de responsabilidades vista en el Curso III, exportando solo el contrato necesario y ocultando los detalles internos. |
Por qué te importan los Sistemas de Tipos aunque delegues la codificación
Cuando delegas la codificación en un agente de IA, una de las diferencias más importantes entre lenguajes o configuraciones es si cuentan con verificación estática de tipos:
- En un entorno sin tipos verificados previamente (dinámico puro), si una función espera recibir
{ importe_centimos: 1200 }pero en otro archivo el agente se equivoca y le pasa{ precio: "1200" }, nadie avisa del error hasta que un usuario real ejecuta justo esa línea en producción. - En un entorno con tipos estáticos estrictos, el propio lenguaje obliga a declarar el contrato de cada estructura y función. Si el agente inventa un nombre de campo que no existe, olvida comprobar qué pasa cuando una búsqueda devuelve «no encontrado» (
nulo) o intenta mezclar un identificador de cliente con un identificador de factura, el verificador de tipos rechaza el código automáticamente antes de ejecutarlo.
Para quien programa la lógica y dirige a un agente de IA, los tipos estáticos funcionan como una red de pruebas lógicas automáticas que verifica que todas las piezas codificadas encajan según sus contratos.
Practica
Un agente te explica la función que ha creado para calcular el importe final de una factura:
«He creado una función llamada procesarFactura. Recibe el objeto factura, le resta el descuento, guarda de paso la factura como PAGADA en la base de datos, envía un correo al cliente y devuelve el número del total calculado».
- Utilizando el concepto de funciones y efectos secundarios, explica por qué resulta peligroso que una función que se usa para «calcular el importe final» modifique al mismo tiempo la base de datos y envíe un correo. (Piensa qué ocurre si solo quieres mostrar una vista previa del importe en pantalla antes de que el cliente pague).
- ¿Cómo dividirías esa responsabilidad en una función pura de cálculo y un procedimiento separado de registro de pago?
- Si el descuento de un cliente es opcional (algunos clientes tienen descuento y otros no tienen ninguno), ¿qué error clásico puede ocurrir al calcular el total si el lenguaje o el modelo no obligan a tratar explícitamente el caso «sin descuento»?
Criterio de comprensión: debes separar el cálculo determinista del importe (función pura sin efectos secundarios, segura de llamar tantas veces como se quiera) de la acción que muta el estado y notifica, y señalar la necesidad de definir el comportamiento explícito ante la ausencia de valor (descuento cero por defecto o rama condicional explícita).
Profundiza con IA
Esta es mi propuesta para separar la función pura de cálculo de los efectos secundarios en
procesarFactura: [tu respuesta]. Evalúa mi respuesta y ponme un ejemplo breve (sin depender de un lenguaje concreto, usando solo contratos de entrada y salida) de cómo un sistema de tipos estricto impediría que alguien pase por error una factura yaANULADAa la operación de cobro.
Siguiente lectura
Una vez que la lógica está escrita en un lenguaje formal con sus tipos y módulos, ¿cómo pasa ese texto a convertirse en un proceso activo y qué diferencia hay entre los errores que se detectan al construir el programa y los que ocurren al usarlo? Continúa con Del texto al proceso: compilación, interpretación y tiempo de ejecución.