Cuando abres un libro de patrones de diseño, el patrón Interpreter suele aparecer casi al final. Es fácil pasarlo por alto pensando: «¿Cuándo se usa esto?».
Sin embargo, al crear una calculadora llegó el momento de calcular directamente expresiones matemáticas en forma de cadena. Ahí el patrón Interpreter encajó a la perfección.
En este artículo crearemos con Swift un intérprete muy pequeño, es decir, un intérprete de un minilenguaje. El objetivo es leer expresiones como 1 + 2 * 3 y devolver el número 7.
La conclusión, en pocas palabras, es esta:
El patrón Interpreter convierte cada regla gramatical en una clase (o enumeración), las ensambla en una estructura de árbol y la recorre recursivamente para obtener el resultado.
Suena complicado, pero al verlo en código resulta más sencillo de lo esperado. Vamos a construirlo juntos.
¿Qué es el patrón Interpreter?
El patrón Interpreter es una forma de crear un «lenguaje pequeño propio» y expresar mediante código las reglas para interpretarlo.
No hablamos de un lenguaje sofisticado. Cualquier expresión pequeña con una gramática definida, como una fórmula, un filtro de búsqueda o un script de reglas de un juego, entra en esta categoría.
La idea central es una sola.
Convierte cada elemento de la gramática en un objeto y haz que esos objetos tengan un método interpret() para interpretarse a sí mismos.
Pensemos, por ejemplo, en la expresión 1 + 2. Contiene el número 1, el número 2 y la operación de suma +.
El número se interpreta como «devolveré mi valor», mientras que la suma se interpreta como «interpretaré el lado izquierdo y el derecho, y los sumaré».
Estas reglas pequeñas forman un árbol; al llamar una vez al intérprete desde la raíz, el cálculo termina al descender por él.
Diseñar un árbol de expresiones en Swift
En Swift, enum encaja especialmente bien con este patrón. Con una enumeración recursiva, la estructura de árbol se expresa de forma muy limpia.
Al principio lo implementé con protocolos y clases, pero al cambiar a enum el código se redujo a la mitad.
Primero definimos una enumeración que represente una expresión: un número individual y los casos de sumar o multiplicar dos expresiones.
Como esta enumeración se contiene a sí misma, hay que añadir la palabra clave indirect.
indirect enum Expr {
case number(Double) // literal numérico
case add(Expr, Expr) // suma
case multiply(Expr, Expr) // multiplicación
}
Ahora creamos una función que interprete el árbol. Procesar cada caso recursivamente es la esencia del patrón Interpreter.
La siguiente función recibe una expresión, calcula su valor numérico real y lo devuelve.
func interpret(_ expr: Expr) -> Double {
switch expr {
case .number(let value):
return value
case .add(let l, let r):
return interpret(l) + interpret(r)
case .multiply(let l, let r):
return interpret(l) * interpret(r)
}
}
A partir de aquí podemos ensamblar 1 + 2 * 3 como un árbol y calcularlo.
Si construimos el árbol a mano como en .add(.number(1), .multiply(.number(2), .number(3))) y lo pasamos a interpret, obtenemos el resultado 7.
¿Cómo se convierte una expresión de texto en un árbol?
Aquí surge una duda: el usuario no introduce un árbol, sino una cadena como "1 + 2 * 3".
El proceso de convertir esa cadena en un árbol se llama parsing, y el código que lo realiza se llama parser.
Siguiendo el enfoque habitual, el parser se divide en dos etapas.
- Lexer: divide la cadena en tokens (por ejemplo:
1,+,2) - Parser: ensambla los tokens en un árbol según las reglas gramaticales
Implementar bien estas dos etapas alargaría demasiado el artículo, así que aquí solo veremos el concepto.
La clave es esta: el patrón Interpreter solo se ocupa de interpretar el árbol. Convertir la cadena en un árbol mediante parsing es otra tarea.
Por eso, durante el aprendizaje recomiendo omitir temporalmente el parser, construir el árbol a mano y completar primero el intérprete. Así se entiende la esencia del patrón.
¿Dónde se usa realmente?
Sinceramente, no es frecuente implementar el patrón Interpreter desde cero. Para un lenguaje complejo, es mucho mejor usar una biblioteca de parsing ya consolidada.
Aun así, entender este patrón aporta mucho.
- Ayuda a hacerse una idea de cómo funciona internamente un motor de expresiones regulares
- Permite entender por qué la sintaxis declarativa de SwiftUI tiene una estructura de árbol
- Puede aplicarse directamente al crear un DSL (Domain-Specific Language, lenguaje específico de dominio) pequeño, como un filtro de búsqueda o un evaluador de expresiones
En especial, cuando la gramática es simple y el alcance reducido, como en una calculadora, un filtro condicional o un script de juego, hacerlo a mano puede resultar más limpio.
Después de aprender este patrón, la estructura de vistas de SwiftUI empezó a parecerme completamente distinta. Cada vista era, en última instancia, un nodo del árbol que se interpreta.
Resumen
Hoy hemos explorado el patrón Interpreter mientras creábamos un intérprete de un minilenguaje en Swift.
Crear un árbol de expresiones con una enumeración recursiva e interpretarlo recursivamente mediante la función interpret. Eso es todo.
Aunque al principio resulte extraño, al calcular 1 + 2 * 3 por tu cuenta llega el momento de «ah, era esto». Te animo a escribir al menos una vez el código aprendido hoy.

