La mayoría de las personas evitan dar descripciones precisas de lo que es una categoría sintáctica, porque si lo hace correctamente con todos los detalles, la relación entre la comprensión y la sofisticación matemática necesaria termina siendo muy, muy baja. El libro de John Reynolds, Teorías de los lenguajes de programación, tiene una de las explicaciones más completas en su capítulo 1, al igual que los Fundamentos prácticos de los lenguajes de programación de Robert Harper .
La intuición que debe tener es que una categoría sintáctica es el conjunto de árboles generados por una gramática libre de contexto. Dada una definición de este tipo para un conjunto de árboles, puede definir funciones en este conjunto utilizando la recursión estructural y probar propiedades sobre ellos mediante la inducción estructural : es decir, analizando las diferentes formas en que se podría construir un árbol.
Por ejemplo, supongamos que tenemos un lenguaje de operaciones aritméticas dado por la siguiente gramática:
e ::= zero | succ(e)| add(e, e)
Luego, podemos definir una función de interpretación eval
que toma un término y le da un número entero, por casos, sobre las formas en que podemos construir un término:
eval : Expr -> Int
eval zero = 0
eval succ(e) = 1 + eval e
eval add(e, e') = eval e + eval e'*
Tenga en cuenta que hemos definido completamente esta función al dar una cláusula por cada posible forma en que podríamos haber generado una expresión a partir de la gramática. El hecho de que esta es una definición completa de una función se llama principio de recursión estructural .
También podemos probar las propiedades de esta función mediante el uso de inducción estructural , haciendo un análisis inductivo para cada caso. Por ejemplo, podemos demostrar que para cada e
, eval e ≥ 0
.
Proof. By structural induction on e.
- Case e = zero:
By the definition of eval, eval zero = 0.
We know 0 ≥ 0 by reflexivity of ≥.
- Case e = succ(e'):
By induction, we know that eval e' ≥ 0
So we also know that 1 + eval e' ≥ eval e'.
By transitivity, 1 + eval e' ≥ 0.
But eval succ(e') = 1 + eval e'.
So eval succ(e') ≥ 0.
- Case e = add(e', e'').
By induction, we know that eval e' ≥ 0.
By induction, we know that eval e'' ≥ 0.
By properties of addition, we know that eval e' + eval e'' ≥ 0.
By the definition of eval, eval add(e',e'') = eval e' + eval e''.
So eval add(e',e'') ≥ 0.
El hecho de que considerar solo los casos de cómo podrían formarse las expresiones constituye una prueba se llama principio de inducción estructural .
Ahora, es un hecho que uno puede definir funciones por recursión estructural y probar propiedades por inducción estructural para cualquier gramática. Sin embargo, demostrar esto rigurosamente requiere una cierta cantidad de teoría de categorías; necesita formalizar categorías sintácticas como álgebras iniciales de una determinada clase de functores, y luego demostrar que tales álgebras iniciales siempre existen para esa clase.
Estas son herramientas realmente pesadas para probar un resultado tan "obvio", por lo que recomiendo confiar en su intuición sobre cómo funcionan las definiciones estructurales, y luego solo molestarse con su semántica detallada si decide convertirse en un lógico profesional.