Anda di halaman 1dari 33

Trabajo Pr

actico Final
Paradigmas de Lenguajes de Programacion (1er cuatrimestre de 2009)

Integrante

LU

Correo electronico

Castillo, Gonzalo

164/06

gonzalocastillo 086@hotmail.com

Martnez, Federico

17/06

federicoemartinez@gmail.com

Sainz-Tr
apaga, Gonzalo

454/06

gonzalo@sainztrapaga.com.ar

En el siguiente trabajo se presenta la implementaci


on de un interprete extensible para C
alculo Lambda tipado. A lo largo
del mismo se desarrollan las principales problem
aticas de implementaci
on, se explica como realizar nuevas extensiones al
c
alculo y se detallan posibles extensiones al trabajo.

Facultad de Ciencias Exactas y Naturales


Universidad de Buenos Aires
Ciudad Universitaria - (Pabell
on I/Planta Baja)
Intendente G
uiraldes 2160 - C1428EGA
Ciudad Aut
onoma de Buenos Aires - Rep. Argentina
Tel/Fax: (54 11) 4576-3359
http://www.fcen.uba.ar

Indice general
1. Introducci
on

1.1. Introducci
on te
orica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.2. Objetivos del trabajo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.3. Organizaci
on del informe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2. Detalles de implementaci
on

2.1. Lenguaje de programaci


on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2. Definici
on de extensiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2.1. Creaci
on de Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2.2. Creaci
on de Expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2.3. Construcci
on de extensiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3. Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3.1. Mecanismo de an
alisis sint
actico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3.2. Definici
on de reglas sint
acticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.4. Tipado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.5. Sem
antica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.6. Tipos y terminos b


asicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.6.1. Boolean, true y false . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.6.2. Abstracciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.6.3. If Then Else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.6.4. Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.6.5. Aplicaci
on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.6.6. Nat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.6.7. Zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.6.8. Succ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.6.9. Pred . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.6.10. isZero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3. Tutorial

18

3.1. La extensi
on Maybe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.2. C
odigo boilerplate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.3. Creando un nuevo tipo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.4. Definici
on de expresiones b
asicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.5. Definici
on de un termino derivado simple

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

3.6. Definici
on de un termino derivado complejo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.7. Creaci
on de la extensi
on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

4. Extensiones

25

4.1. Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.2. Expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

5. Posibles extensiones al trabajo

27

5.1. Subtipado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
5.2. Inferencia de tipos y otras alternativas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

6. Conclusi
on

30

Castillo, Martnez, Sainz-Tr


apaga

Pagina 1 de 30

Parte 1

Introducci
on
1.1.

Introducci
on te
orica

El C
alculo Lambda es un modelo de computaci
on basado en funciones. Por tratarse de un modelo computacionalmente
completo y riguroso en su formulaci
on, se utiliza con frecuencia como herramienta para el estudio de lenguajes de programaci
on y sus propiedades, as como lenguaje de referencia para la definici
on de sem
antica en otros lenguajes de programaci
on.
La versi
on del C
alculo Lambda desarrollada en este trabajo es el C
alculo Lambda Tipado (A. Church, 19401 ).

1.2.

Objetivos del trabajo

El trabajo propuesto consiste en el desarrollo de un interprete para C


alculo Lambda Tipado, con el foco fijado en la
facilidad de extensi
on del mismo. Durante el cuatrimestre se utiliz
o una definici
on b
asica del C
alculo que se extendi
o progresivamente agregando nuevas funcionalidades propias de los distintos paradigmas de programaci
on. La idea del interprete
desarrollado era adaptarse al desarrollo propuesto en la materia, de modo que agregar nuevas extensiones al c
alculo sea una
tarea tan simple como sea posible.
La facilidad de extensi
on se da a traves del uso del paradigma orientado a objetos y el uso intensivo de herencia como
herramienta de reuso de c
odigo, minimizando as la cantidad de lneas necesarias para la creaci
on de una extensi
on. Dada
esta facilidad, debera ser factible incorporar al trabajo como complemento de la materia por la capacidad que provee de
permitir a los alumnos interactuar de forma m
as directa con el modelo.
Finalmente, adem
as del sistema b
asico y f
acilmente extensible, se incluyen adem
as con el trabajo la mayora de las
extensiones que fueron propuestas en clase durante el cuatrimestre, y documentaci
on suficiente como para que agregar
nuevas extensiones sea una tarea accesible.

1.3.

Organizaci
on del informe

El presente informe se organiza de la siguiente manera:


En el apartado 2 se explican los detalles concernientes a la implementaci
on del interprete, as como las decisiones de
dise
no que fueron tomadas a la hora de desarrollar.
En 3 se detalla paso a paso la construcci
on de una nueva extensi
on, con el objetivo de familiarizar al lector con el
problema y la soluci
on como la proponemos.
En 4 se enumeran las extensiones ya implementadas por nosotros.
Por u
ltimo, en 5 comentamos posibles extensiones o mejoras que podran realizarse al trabajo.
1 A.

Church: A Formulation of the Simple Theory of Types, JSL 5, 1940

Castillo, Martnez, Sainz-Tr


apaga

Pagina 2 de 30

Parte 2

Detalles de implementaci
on
2.1.

Lenguaje de programaci
on

Para la implementaci
on del interprete utilizamos el lenguaje de programaci
on Python, en parte por tratarse de un
lenguaje con el que estamos acostumbrados a trabajar, pero adem
as porque consideramos que su sintaxis sencilla y limpia
es adecuada para facilitar la construcci
on posterior de extensiones, a
un por personas que no esten familiarizadas con el
lenguaje.

2.2.

Definici
on de extensiones

Conceptualmente, el interprete concibe a un lenguaje como una colecci


on de extensiones. Una extensi
on consta de un
nombre apropiado para identificarla, una colecci
on de tipos y una colecci
on de terminos, as como las reglas necesarias para
darles tipado, sintaxis y sem
antica a las expresiones del lenguaje extendido.
Esta idea reproduce la aproximaci
on ofrecida en clase, en la que se parte de un c
alculo b
asico con algunos elementos
esenciales, y sobre el que se van construyendo nuevas estructuras.
Como dijimos, la caracterstica principal de esta implementaci
on es que permite agregar extensiones (es decir, tipos y
expresiones). As, en lo que respecta al c
odigo, crear nuevas extensiones consiste en subclasear dos clases llamadas Expresion
y Tipo que residen en expresion.py.

2.2.1.

Creaci
on de Tipos

Para crear un nuevo tipo, se debe heredar de la clase Tipo y asegurarse de implementar los siguientes metodos:
init (self, tok): el constructor de una instancia de un tipo, que toma una lista de tokens (ver 2.3) y a partir
de estos construye la instancia. En general, al momento de ser procesados por este constructor, los tokens ya fueron
procesados y son objetos que representan a su vez a otros tipos (an
alogo al funcionamiento de un fold ), y son necesarios
para la creaci
on de tipos recursivos.
sintaxis(cls): un classmethod o metodo est
atico que define la sintaxis con la que se va a parsear una expresi
on de
tipo1 .
eq (self,other): la comparaci
on por igualdad entre tipos, que debe funcionar como la relaci
on unifica. Por defecto
la clase padre Tipo considera que un tipo unifica con otro si son de la misma clase, por lo cual si este comportamiento
es el esperado no es necesario definirlo (por ejemplo, Nat unifica con Nat, pero para tipos recursivos podra no ser
suficiente esta definici
on).
1 Nota: No confundir expresi
on de tipo con expresiones tipadas del c
alculo. La clase hija de Tipo define la sintaxis que utiliza el
lenguaje para referirse al tipo propiamente dicho, por ejemplo, en las declaraciones de funciones. La sintaxis de los t
erminos que tipan
a este tipo es competencia de las clases hijas de expresi
on, que se detallan m
as adelante

Castillo, Martnez, Sainz-Tr


apaga

Pagina 3 de 30

str (self ): (optativo) el equivalente a toString en otros lenguajes, que se utiliza para imprimir por pantalla a las
instancias de la clase.

2.2.2.

Creaci
on de Expresiones

Para crear una nueva expresi


on v
alida dentro del lenguaje, se debe heredar de la clase Expresion y asegurarse de
implementar los siguientes metodos:
init (self, tok): el constructor, que construye una instancia de la expresi
on a partir de una lista de tokens (ver
2.3).
sintaxis(cls): an
alogo a la extensi
on de tipos, este metodo est
atico define la sintaxis de una expresi
on de esta clase
(ver 2.3).
reducir(self ): implementa la semantica de la expresi
on (ver 2.5).
tipar(self, namespace): implementa las reglas de tipado de la expresi
on (ver 2.4).
sustituir(self, var, expresion): implementa las reglas de sustituci
on para las instancias, donde var es el nombre de
una variable a ser reemplazada por expresion. Es aqu donde se determina, entre otras cosas, el scope de las variables.
str (self ): (optativo) el equivalente a toString en otros lenguajes, que se utiliza para imprimir por pantalla a las
instancias de la clase.

2.2.3.

Construcci
on de extensiones

Finalmente, una extensi


on se modela como una instancia de la clase Extensi
on, que se construye a partir de una etiqueta,
una lista de expresiones y una lista de tipos. Los elementos de la listas son las clases que mencionamos previamente. As, puede
construirse un lenguaje a partir de una serie de extensiones que se cargan o descargan din
amicamente. El procedimiento se
detalla con mayor precisi
on en 3.

2.3.
2.3.1.

Sintaxis
Mecanismo de an
alisis sint
actico

Uno de los problemas principales a resolver para permitir la posterior definici


on de extensiones era como facilitar la
definici
on de la sintaxis de los nuevos terminos sin obligar al usuario a interactuar de forma directa con el parser utilizado.
El desafo consisti
o adem
as en dar una forma sencilla de definir la sintaxis, pero sin imponer restricciones innecesarias a la
complejidad de las extensiones que podran definirse.
Las herramientas que conocemos que permiten definir sintaxis y sem
antica de forma combinada y sin demasiado c
odigo
de por medio son las de Gram
aticas de Atributos y Traducci
on Dirigida por Sintaxis. Sin embargo, consideramos que lidiar
con las particularidades de las gram
aticas libres de contexto era algo a evitar, por lo que buscamos una alternativa m
as
simple.
La soluci
on elegida es intermedia. Por un lado, se logr
o que definir la sintaxis (y su correspondiente sem
antica) sea
relativamente sencillo, abstrayendo la mayor parte del c
odigo com
un, y manteniendo una sintaxis medianamente simple. Por
otra parte, varios de los helpers introducidos para simplificar la creaci
on de extensiones pueden omitirse para as tener m
as
flexibilidad a la hora de trabajar. Esto se debe a que dichos helpers se definen en su mayora como funciones auxiliares que
est
an debilmente acopladas al resto del interprete, siendo as su uso totalmente optativo.
El parser elegido corresponde a la familia de parsers recursivos descendentes, y utilizamos la implementaci
on de la librera
PyParsing por el uso excelente que hace de la sobrecarga de operadores y de las capacidades de alto nivel de Python para
permitir la definici
on amigable de reglas gramaticales utilizando Python de forma directa, sin recurrir a definicies externas
en otros lenguajes.
El parser utiliza backtracking, porque de otro modo sera imposible permitir a
nadir de forma simple nuevas reglas
sint
acticas que podran introducir ambig
uedades en parsers recursivos. Este problema proviene del hecho de que los parsers
recursivos descendentes son una familia similar a los LL(1), y por tanto lidian de forma limitada con los posibles prefijos de

Castillo, Martnez, Sainz-Tr


apaga

Pagina 4 de 30

una definici
on gramatical. Si bien algunos de los problemas de los parsers LL(1) se eliminan a costa de usar backtracking,
otros persisten: no es posible utilizar recursi
on a izquierda en la definici
on de reglas. Esta es una limitaci
on propia del
mecanismo de parsing que nos oblig
o a realizar algunas modificaciones en el lenguaje aceptado por el interprete.
As, por ejemplo, para el caso de la aplicaci
on, la producci
on:
Exp Exp Exp
no puede ser parseada por este procedimiento (dado que el programa entrara en un bucle infinito hasta terminar por stack
overflow. Por lo tanto, en su lugar proponemos:
Exp (Exp Exp)
La gram
atica sigue siendo ambigua, pero al eliminar la recursi
on a izquierda mediante la introducci
on de parentesis, el
parser puede eliminar la ambiguedad utilizando alguna heurstica de decisi
on (sea first-match o longest-match, seg
un lo que
uno considere m
as conveniente). Esto elimina una preocupaci
on a la hora de definir nuevas extensiones.
Por u
ltimo, es importante mencionar que las expresiones del lenguaje, a excepci
on de los terminos de tipo y las variables,
no deber
an utilizar letras may
usculas ya que este criterio se utiliza para diferenciar entre s a estos diferentes elementos.

2.3.2.

Definici
on de reglas sint
acticas

Como se mencion
o antes, es el metodo est
atico sintaxis() para expresiones el que devuelve el lado derecho de una
producci
on que se utilizar
a al momento de parsear una expresi
on. Este lado derecho se asocia al no terminal Exp de la
gram
atica, que es el smbolo inicial que produce todos los terminos del lenguaje, y puede ser usado en la definici
on de la
sintaxis para referirse (recursivamente) a cualquier termino. Su an
alogo TipoExp caracteriza a las expresiones de tipos y
puede a su vez usarse en las definiciones de sintaxis.
Para la definici
on de la sintaxis se pueden utilizar directamente las distintas clases que provee PyParsing, y sobre las
que hay excelente documentaci
on en el sitio web correspondiente. Por ejemplo, la sintaxis del if resultara:
Exp if Exp then Exp else Exp
Utilizando las clases de PyParsing:
Keyword(if ).suppress() + Exp + Keyword(then).suppress() + Exp + Keyword(else).suppress() + Exp
N
otese que la sintaxis es simple, utilizando el operando de suma para la concatenaci
on y las referencias a Exp cuando
es necesario indicar que en ese lugar aparece una expresi
on arbitraria. La lista de tokens que se construye a partir de esa
expresi
on es la que luego recibe el constructor de la expresi
on para instanciar un objeto.
El metodo suppress() elimina el token despues de hallarlo porque no resulta de interes para su utilizaci
on posterior
(puesto que no contiene informaci
on). As, se eliminan todos los strings fijos de la expresi
on conservando as solo las
subexpresiones, que son las que interesan al momento de construir una instancia del objeto correspondiente a la expresi
on
if. N
otese que no es necesario utilizar suppress(), pero de no hacerlo se deber
an ignorar los tokens en el constructor de la
expresi
on.
Sin embargo, para sintaxis simples puede usarse el helper expresion.makeSintaxis(*args), que recibe como par
ametros
los componentes sint
acticos para armar la producci
on. Asi por ejemplo, para definir la sintaxis del if:
makeSintaxis(if ,Exp,then,Exp,else,Exp)
La funci
on makeSintaxis transforma las cadenas de letras en Keywords, las cadenas que contengan smbolos en Literals, y
las Exp (o cualquier otra instancia de parseElement) las mantiene, y devuelve la expresi
on que resulta de la concatenaci
on

Castillo, Martnez, Sainz-Tr


apaga

Pagina 5 de 30

de todas ellas. Si bien sintaxis m


as complejas (como el caso de los registros con campos nombrados) no pueden definirse con
makeSintaxis, por lo que ser
a necesario utilizar el metodo anterior, m
as extenso pero m
as flexible.
Como se dijo anteriormente, al parsear una expresi
on segun esta sintaxis, se pasan los tokens al constructor para construir
el objeto apropiado. Los tokens son todos las instancias de parseElement que no tengan suppress activado. En el caso del
if, los tokens son las tres instancias de Exp. Notar que al constructor del if llegar
a entonces una lista con tres elementos
que son los resultados de haber parseado recursivamente las 3 expresiones (y por lo tanto son instancias de alguna subclase
de Expresion).

2.4.

Tipado

Dado que implementamos un lambda calculo tipado, un elemento fundamental en la definicion de nuevas expresiones son
las reglas de tipado. El metodo debe devolver una instancia de alguna subclase de Tipo indicando el tipo correspondiente o
debe generar TypeException en caso de que el termino no tipe.
Para definir reglas de tipado se puede usar el = entre tipos, por esta raz
on es necesario que las subclases de Tipo
implementen un eq adecuado a su sem
antica.
La funci
on tipar recibe ademas como par
ametro el contexto de tipado, que funciona como diccionario de nombre de
variable (string) a su tipo.

2.5.

Sem
antica

La sem
antica en nuestra implemetanci
on est
a dada por el metodo reducir. Esta reducci
on es del tipo big-step, es decir
si un termino tipa, una llamada a reducir debe devolver el valor al que reduce.
A la hora de definir la sem
antica, puede asumirse como precondici
on que el termino tipa, ya que el interprete chequea
previamente que la expresi
on tipe antes de intentar reducirla. Es importante asegurarse de que si el termino tipa, la
reducci
on no deberia fallar. De esta manera el metodo reducir debe devolver la instancia de expresi
on que resulta de reducir
completamente al termino.

2.6.

Tipos y t
erminos b
asicos

En esta secci
on presentaremos los tipos b
asicos vistos en clase junto con su implementaci
on para nuestro lenguaje.
Consideraremos como tipos b
asicos a los booleanos, los naturales y a las funciones.
Es interesante notar que estos no son objetos privilegiados dentro de la jerarqua del interprete, y se definen exactamente
de la misma manera en que se definira cualquier extensi
on. Sin embargo, por su naturaleza esencial, son requeridos por casi
todas las dem
as extensiones y por tanto son de interes especial.

2.6.1.

Boolean, true y false

T
erminos

M ::= true|f alse

Castillo, Martnez, Sainz-Tr


apaga

Pagina 6 de 30

Reglas de tipado

. true : Bool

. f alse : Bool
Sem
antica
Las expresiones true y false son valores, no reducen.

Implementaci
on
Esta implementaci
on, por su sencillez, hace uso de otros dos helpers apropiados para la construcci
on de tipos b
asicos
(no parametricos) y a
tomos de alg
un tipo particular. Se trata de las funciones simpleTypeFactory (que crea una clase
apropiada a partir de la sintaxis del termino de tipo) y atomoFactory (que crea una clase hija de Expresion a partir de su
sintaxis simple y la clase correspondiente a su tipo).
Estas dos funciones se utilizan en varias ocasiones cuando es necesario definir casos sencillos, ahorrando as la repetici
on
innecesaria de c
odigo en los lugares donde no es necesaria la flexibilidad.

Boolean = simpleTypeFactory(Boolean)
Verdadero = atomoFactory(true, Boolean)
Falso = atomoFactory(false, Boolean)

2.6.2.

Abstracciones

T
erminos

M ::= ...|X : .M

Reglas de tipado

, X : . M :
. X : .M :
Sem
antica
Las abstracciones son valores, no reducen.

Castillo, Martnez, Sainz-Tr


apaga

Implementaci
on

class Func(Tipo):
def

init (self,tok):
"""
Define para el tipo funcion el dominio y la imagen.
"""
dom, img = tok
self.dominio = dom
self.imagen = img

def

eq (self, other):
"""
Un tipo es igual a un tipo funcion, si es de tipo funcion
y sus dominios e imagenes son iguales.
"""
return self. class == other. class and \
self.dominio == other.dominio and \
self.imagen == other.imagen
@classmethod
def sintaxis(cls):
Abs = makeSintaxis((, TipoExp, -> , TipoExp, ) )
return Abs
def

str (self):
s1 = str(self.dominio)
s2 = str(self.imagen)
if self.dominio. class == self. class :
return "( %s) -> %s" % (s1, s2)
else:
return " %s -> %s" % (s1, s2)

class Abstraccion(Expresion):
def

init (self, toks):


"""
Una Abstraccion se compone por un id que representa una variable,
un tipo para esa variable y un expresion.
"""
var, tipo, expresion = toks
self.var = var
self.tipoVar = tipo
self.expresion = expresion

def reducir(self):
"""
Una Abstraccion reduce a si misma, es un valor.
"""
return self
def tipar(self, namespace):
"""
gamma,{X:alpha} | > M : beta
---------------------------gamma | > \X:alpha.M : (alpha -> beta)
"""
nam2 = dict(namespace)
nam2[self.var] = self.tipoVar
return Func([self.tipoVar, self.expresion.tipar(nam2)])

Pagina 7 de 30

Castillo, Martnez, Sainz-Tr


apaga

Pagina 8 de 30

def sustituir(self, var, expresion):


"""
\X:alpha.M {X <- T} --> \X:alpha.M
\X:alpha.M {Y <- T} --> \X:alpha.(M {Y <- T}) si X != Y
"""
if self.var != var:
expresion = self.expresion.sustituir(var, expresion)
return Abstraccion([self.var, self.tipoVar, expresion])
return self
@classmethod
def sintaxis(cls):
Abs = makeSintaxis(\\,
return Abs
def

2.6.3.

Id , :, TipoExp , ., Exp)

str (self):
return "\\ %s : %s . %s" % (self.var, self.tipoVar, self.expresion)

If Then Else

T
erminos

M ::= ...|if M then P else Q

Reglas de tipado

. M : Bool, . P : , . Q :
. if M then P else Q :
Sem
antica

M M
if M then P else Q if M then P else Q

if true then P else Q P

if f alse then P else Q Q

Castillo, Martnez, Sainz-Tr


apaga

Implementaci
on

class IfThenElse(Expresion):
def

init (self, toks):


"""
Define para la estructura IfThenElse la guarda y las
ramas por verdadero y por falso.
"""
guarda, ramaTrue, ramaFalse = toks
self.guarda = guarda
self.ramaTrue = ramaTrue
self.ramaFalse = ramaFalse

def reducir(self):
"""
Reducci
on de la guarda a un valor. Luego dependiendo de dicho valor
se reduce la rama verdadera o la falsa.
"""
if isinstance(self.guarda.reducir(), Verdadero):
return self.ramaTrue.reducir()
else:
return self.ramaFalse.reducir()

def tipar(self, namespace):


"""
gamma | > Guarda : Boolean, gamma | > RamaTrue : alpha, gamma | > RamaFalse : alpha
--------------------------------------------------------------gamma | > if Guarda then RamaTrue else RamaFalse : alpha
"""
tipoGuarda = self.guarda.tipar(namespace)
tipoRamaTrue = self.ramaTrue.tipar(namespace)
tipoRamaFalse = self.ramaFalse.tipar(namespace)
# gamma | > Guarda : Boolean
if tipoGuarda == Boolean([]):
# gamma | > RamaTrue : alpha, gamma | > RamaFalse : alpha
if tipoRamaTrue == tipoRamaFalse:
# gamma | > if Guarda then RamaTrue else RamaFalse : alpha
return tipoRamaTrue
else:
raise TypeException(Tipo rama true: %s \n % tipoRamaTrue + \
Tipo rama false: %s \n % tipoRamaFalse + \
No existe unificaci
on entre los tipos de las ramas.)
else:
raise TypeException(Tipo de la guarda: %s \n % tipoGuarda + \
El tipo de la guarda no unifica con Boolean.)

def sustituir(self, var, expresion):


"""
if M then N else O {X <- T} --> if M {X <- T} then N {X <- T} else O {X <- T}.
"""
guarda = self.guarda.sustituir(var, expresion)
ramaTrue = self.ramaTrue.sustituir(var, expresion)
ramaFalse = self.ramaFalse.sustituir(var, expresion)
return IfThenElse([guarda, ramaTrue, ramaFalse])
@classmethod
def sintaxis(cls):

Pagina 9 de 30

Castillo, Martnez, Sainz-Tr


apaga

Pagina 10 de 30

# if M then N else O
If = makeSintaxis(if , Exp,then, Exp,else, Exp)
return If
def

2.6.4.

str (self):
return "if %s then %s else %s" % (self.guarda, self.ramaTrue, self.ramaFalse)

Variables

T
erminos

es un conjunto infinito enumerable de variables, X ,

M ::= ...|X

Reglas de tipado

{X : }
.X :
Sem
antica
Las variables no reducen, tienen que ser sustitudas.

Implementaci
on
class Variable(Expresion):
def

init (self, tok):


"""
Las variables se inicializan con un identificador
compuesto por un string con el primer caracter en mayuscula.
"""
self.id = tok[0]

def reducir(self):
"""
Las variables reducen a si mismas, tiene que ser sustituidas.
"""
return self
def tipar(self, namespace):
"""
{X : alpha} pertenece a gamma
---------------------------gamma | > X : alpha
"""
if not (self.id in namespace):
for each in namespace:

Castillo, Martnez, Sainz-Tr


apaga

Pagina 11 de 30

print each, namespace[each], each. class


raise TypeException((No es posible determinar el tipo de la variable %s a + \
partir del contexto: %s.) % (self.id, namespace))
return namespace[self.id]
def sustituir(self, var, expresion):
"""
X {X <- T} --> T
X {Y <- T} --> X si X != Y
"""
if self.id == var:
return expresion
else:
return self
@classmethod
def sintaxis(cls):
Id = Regex([A-Z][a-zA-Z]*)
return Id
def

2.6.5.

str (self):
return self.id

Aplicaci
on

T
erminos

M ::= ...|M N

Reglas de tipado

. M : , . N :
.M N :
Sem
antica

M M
M N M N
N N
V N V N
(X : .M )V M {X V }

Castillo, Martnez, Sainz-Tr


apaga

Pagina 12 de 30

Implementaci
on

class Aplicacion(Expresion):
def

init (self, toks):


"""
Una aplicacion esta compuesta por una funcion aplicadora y
un parametro.
"""
aplicador, parametro = toks
self.aplicador = aplicador
self.parametro = parametro

def reducir(self):
"""
Se reduce la funcion aplicadora y el parametro, luego:
(\X:alpha.M V) --> M {X <- V}
Finalmente se sustituye M {X <- V} y se reduce M.
"""
aplicador = self.aplicador.reducir()
parametro = self.parametro.reducir()
res = aplicador.expresion.sustituir(aplicador.var, parametro)
return res.reducir()

def tipar(self, namespace):


"""
gamma | > M: (alpha -> beta), gamma | > N: alpha
-----------------------------------------------gamma | > (M N) : beta
"""
x = self.aplicador.tipar(namespace)
z = self.parametro.tipar(namespace)
if isinstance(x, Func):
if x.dominio == z:
return x.imagen
else:
raise TypeException((Tipo del aplicador: %s \n+ \
Tipo del parametro: %s \n+ \
El tipo del parametro no se corresponde con el domino del tipo del aplicador.
(x'

else:
raise TypeException((Tipo del aplicador: %s \n+ \
El tipo del aplicador no se corresponde con el tipo de una Abstraccion.) %
x)
def sustituir(self, var, expresion):
"""
(M N) {X <- T} --> (M {X <- T} N {X <- T})
"""
aplicador = self.aplicador.sustituir(var, expresion)
parametro = self.parametro.sustituir(var, expresion)
return Aplicacion([aplicador, parametro])
@classmethod
def sintaxis(cls):
App = makeSintaxis((, Exp, White().suppress(), Exp,))
return App

Castillo, Martnez, Sainz-Tr


apaga

def

2.6.6.

Pagina 13 de 30

str (self):
return "( %s %s)" % (str(self.aplicador), str(self.parametro))

Nat

Implementaci
on

Nat = simpleTypeFactory(Nat)

2.6.7.

Zero

T
erminos

M ::= ...|zero

Reglas de tipado

. zero : N at
Sem
antica
zero no reduce, es un valor.

Implementaci
on

Zero = atomoFactory(zero, Nat)

2.6.8.

Succ

T
erminos

M ::= ...|succ(M )

Castillo, Martnez, Sainz-Tr


apaga

Pagina 14 de 30

Reglas de tipado

. M : N at
. succ(M ) : N at
Sem
antica

M M
succ(M ) succ(M )
Implementaci
on

class Succ(Expresion):
def

init (self, toks):


"""
Define para estructura succ la expresion que contiene.
"""
self.termino = toks[0]

def reducir(self):
"""
Reducir succ(E) corresponde a reducir E.
"""
terminoRed = self.termino.reducir()
return Succ([terminoRed])
def tipar(self, namespace):
"""
gamma | > E : Nat
----------------gamma | > succ(E) : Nat
"""
if self.termino.tipar(namespace) == Nat([]):
return Nat([])
raise TypeException((El tipo %s de la expresion: %s \n+ \
no se corresponde con el tipo Nat.) %
(self.termino.tipar(namespace), self.termino))
def sustituir(self, var, expresion):
"""
succ(E) {X <- T} --> succ(E {X <- T})
"""
return Succ([self.termino.sustituir(var, expresion)])
@classmethod
def sintaxis(cls):
succ = makeSintaxis(succ(, Exp, ))
return succ
def

str (self):

Castillo, Martnez, Sainz-Tr


apaga

Pagina 15 de 30

return "succ( %s)" % self.termino

2.6.9.

Pred

T
erminos

M ::= ...|pred(M )

Reglas de tipado

. M : N at
. pred(M ) : N at
Sem
antica

M M
pred(M ) pred(M )

pred(succ(M )) M

pred(zero) zero
Implementaci
on

class Pred(Expresion):
def

init (self, toks):


"""
Define para estructura succ la expresion que contiene.
"""
self.termino = toks[0]

def reducir(self):
"""
Se reduce primero el la expresion que contiene pred, luego:
pred(zero) --> zero
pred(succ(v)) --> v
"""

Castillo, Martnez, Sainz-Tr


apaga

Pagina 16 de 30

termino = self.termino.reducir()
if isinstance(termino, Zero):
return termino
else:
return termino.termino
def tipar(self, namespace):
"""
gamma | > E : Nat
----------------gamma | > pred(E) : Nat
"""
if self.termino.tipar(namespace) == Nat([]):
return Nat([])
raise TypeException((El tipo %s de la expresion: %s \n+\
no se corresponde con el tipo Nat.) %
(self.termino.tipar(namespace), self.termino))
def sustituir(self, var, expresion):
"""
pred(E) {X <- T} --> pred(E {X <- T})
"""
return Pred([self.termino.sustituir(var, expresion)])
@classmethod
def sintaxis(cls):
pred = makeSintaxis(pred(, Exp, ))
return pred
def

str (self):
return "pred( %s)" % self.termino

2.6.10.

isZero

T
erminos

M ::= ...|isZero(M )

Reglas de tipado

. M : N at
. isZero(M ) : Bool
Sem
antica

M M
isZero(M ) isZero(M )

Castillo, Martnez, Sainz-Tr


apaga

Pagina 17 de 30

isZero(succ(M )) f alse

isZero(zero) true
Implementaci
on

class IsZero(Expresion):
def

init (self, toks):


"""
Se define para la estructura isZero la expresion que contiene.
"""
self.termino = toks[0]

def reducir(self):
"""
Se reduce primero la expresion que contiene isZero, luego:
isZero(zero) --> true
isZero(succ(v)) --> false
"""
termino = self.termino.reducir()
if isinstance(termino, Zero):
return Verdadero([])
else:
return Falso([])
def tipar(self, namespace):
"""
gamma | > E : Nat
---------------gamma | > isZero(E): Boolean
"""
if self.termino.tipar(namespace) == Nat([]):
return Boolean([])
else:
raise TypeException((El tipo %s de la expresion %s no se corresponde con el tipo Nat.) \
% (self.termino.tipar(namespace), self.termino))
def sustituir(self, var, expresion):
"""
isZero(E) {X <- T} --> isZero(E {X <- T})
"""
return IsZero([self.termino.sustituir(var, expresion)])
@classmethod
def sintaxis(cls):
isZ = makeSintaxis(isZero(, Exp, ))
return isZ
def

str (self):
return "isZero( %s)" % self.termino

Castillo, Martnez, Sainz-Tr


apaga

Pagina 18 de 30

Parte 3

Tutorial
3.1.

La extensi
on Maybe

En este tutorial vamos a realizar paso por paso la extensi


on que llamamos Maybe, y que nos permite definir un tipo
parametrico M aybe < T > que tiene dos constructores: N othing < T > y Just J (donde J es un termino de tipo T).
Para construir la extensi
on, tenemos que:
crear el tipo
crear las expresiones b
asicas Nothing y Just
crear una funci
on simple: isNothing
crear una funci
on m
as compleja: caseMaybe
crear la extensi
on propiamente dicha y registrarla con el interprete

3.2.

C
odigo boilerplate

Para crear la nueva extensi


on creamos un nuevo archivo de texto vaco en la carpeta extensiones (idealmente con
extensi
on .py) y pegamos el siguiente c
odigo en el:

#!/usr/bin/python
# -*- coding: utf8 -*from expresion import Expresion, Tipo, Exp, TipoExp, TypeException
from expresion import makeSintaxis
from booleans import Boolean
from lenguaje import Extension

Como ver
an, se trata de una serie de imports de objetos que vamos a necesitar referenciar en nuestro c
odigo. Expresion
y Tipo son las clases de las que vamos a heredar para construir los terminos y tipos de nuestra extensi
on (que se construye
a partir de la clase Extension, que importamos al final de todo).
Exp y TipoExp son los patrones de sintaxis de PyParsing que podemos usar al definir sintaxis para referirnos a una
expresi
on cualquiera o n termino de tipo cualquiera. TypeException es la excepci
on que debemos producir cuando haya
un error de tipos
Finalmente, Boolean es la clase que corresponde al tipo hom
onimo (y por tanto vive en la extensi
on correspondiente). Es

Castillo, Martnez, Sainz-Tr


apaga

Pagina 19 de 30

necesaria porque m
as adelante vamos a necesitar indicarle al sistema de tipado que un termino es de tipo Boolean (adivinan
cual?), y para esto es necesario instanciar dicha clase.

3.3.

Creando un nuevo tipo

En este caso no se puede utilizar el helper simpleTypeFactory porque este no es un tipo simple: se trata de un tipo
parametrico, y por lo tanto hay que definirlo a mano extendiendo directamente la clase Tipo. Comencemos entonces por
definir la sintaxis:

#######################################
# Declaraci
on del nuevo tipo Maybe(T) #
#######################################
class TipoMaybe(Tipo):
@classmethod
def sintaxis(cls):
return makeSintaxis(Maybe(, TipoExp, ))

Esta declaraci
on decorada (la lnea que comienza con @ se llama decorator en Python) crea un metodo est
atico de
la clase TipoMaybe (que luego se llama como TipoMaybe.sintaxis()). En este caso utilizamos el helper makeSintaxis para
decirle al interprete que un termino que describe al tipo TipoMaybe tiene la sintaxis Maybe(TipoExp), donde TipoExp
representa a una expresi
on de tipo cualquiera (por ejemplo, Nat, Bool o incluso Maybe(Nat)!).
La definici
on sin makeSintaxis hubiera sido m
as larga y difcil de leer(y adem
as hubiera sido necesario importar Literal
desde pyparsing!):

return Literal(Maybe().suppress() + TipoExp + Literal()).suppress()

Veamos ahora como se construye una instancia de TipoMaybe:

def

init (self, toks):


self.tipo = toks[0]

La construcci
on es simple, u
nicamente se almacena como un atributo de instancia el primer elemento de la lista toks,
que corresponde al primer y u
nico token que matchea la sintaxis del tipo (recordemos que como se utiliza suppress()
implcitamente sobre los chunks Maybe( y ), estos no ser
an recibidos por el constructor). Sigamos:

def

eq (self, otro):
return self. class == otro. class
self.tipo == otro.tipo

and \

Un T ipoM aybe < T > ser


a igual a otro si el segundo es un TipoMaybe (esa es la implementaci
on heredada de la clase
Tipo, y no sera necesario sobrecargarla si fuera esta la definici
on), pero tambien si el tipo englobado por el Maybe es
igual al otro. Recordemos que si bien se utiliza el operador de igualdad, la noci
on asociada al mismo es la de unificaci
on.
def

str (self):
return Maybe( %s)" % self.tipo

Finalmente, el u
ltimo metodo define la forma en que se convierte el objeto a una representaci
on en forma de string
amigable para el usuario. En este caso (y en todos los dem
as), nos limitamos a reproducir la sintaxis.
Con esto ya tenemos el nuevo tipo definido, y podemos dedicarnos a construir los terminos asociados al mismo.

Castillo, Martnez, Sainz-Tr


apaga

3.4.

Pagina 20 de 30

Definici
on de expresiones b
asicas

A continuaci
on vamos a definir las dos expresiones b
asicas del tipo Maybe(T), empezando por Nothing (y esta vez
heredando de Expresion en lugar de Tipo).

######################################
# Declaraci
on de nuevas expresiones #
######################################
class Nothing(Expresion):
@classmethod
def sintaxis(cls):
return makeSintaxis(nothing(, TipoExp, ))

La definici
on de sintaxis es an
aloga a la definici
on de sintaxis en el termino de tipo. Hay dos particularidades para notar
en esta definici
on. La primera es que la expresi
on que definimos como nothing(T) consta de una variable de tipo(denotada
por TipoExp) que permite tipar la expresi
on. En segundo lugar, no hay que olvidar que los terminos no deben llevar
may
usculas (ya que el parser asume que las cosas que comienzan por may
usculas dentro de una expresi
on son variables).
Por esta raz
on, el a
tomo creado se llama nothing(T) y no Nothing(T).

def

init (self, toks):


self.tipo = toks[0]

def

str (self):
return nothing( %s) % self.tipo

Tanto el constructor como la funci


on de conversi
on a string son exactamente iguales a las de la definici
on del tipo y por
tanto no requieren explicaci
on adicional. Veamos ahora que ocurre con las funciones propias de la clase Expresion.
def reducir(self):
return self

La funci
on reducir() es responsable de producir un termino reducido (con sem
antica big-step) a partir de la expresi
on
actual. Sin embargo, en el caso de Nothing y por tratarse de un valor, no hay que hacer ninguna reducci
on y es suficiente
con devolver una referencia al propio objeto que recibe el mensaje.
def tipar(self, namespace):
return TipoMaybe([self.tipo])

La funci
on tipar() se encarga de producir una instancia del tipo correspondiente a esta expresi
on. Para esto, nos servimos
de la clase que definimos anteriormente que instanciamos parametrizada en el tipo que parseamos a partir de la sintaxis.
As, convertimos nothing(Nat) en una instancia de T ypeM aybe < N at >.
N
otese la peculiaridad de que TipoMaybe recibe una lista de tokens, y por lo tanto se debe pasar como par
ametro
[self.tipo] (entre corchetes).
def sustituir(self, var, expresion):
return self

Finalmente, el mecanismo de sustituci


on, por tratarse de un a
tomo inmutable, se limita a devolver una referencia al
propio objeto sin sustituir nada (ya que no pueden aparecer variables dentro de esta expresi
on).
Veamos ahora la definici
on de Just J:

Castillo, Martnez, Sainz-Tr


apaga

Pagina 21 de 30

class Just(Expresion):
@classmethod
def sintaxis(cls):
return makeSintaxis(just(, Exp, ))

En este caso la diferencia respecto de la definici


on de nothing reside en que la subexpresi
on es un termino convencional
y no una declaraci
on de tipo. Esto es posible puesto que a partir de dicho termino se podr
a inferir su tipo y as establecer
el tipado de esta expresi
on. Esto se refleja en la utilizaci
on de Exp en lugar de TipoExp dentro de la definici
on de sintaxis.

def

init (self, toks):


self.exp = toks[0]

def

str (self):
return just( %s) % self.exp

def reducir(self):
e = self.exp.reducir()
return Just([e])

La definici
on de reducci
on se ajusta a lo definido por el C
alculo Lambda: si M M luego Just(M) Just(M). Esto
es precisamente lo que se establece aqu, con una llamada recursiva a reducir() de la expresi
on hija.
def tipar(self, namespace):
return TipoMaybe([self.exp.tipar(namespace)])
def sustituir(self, var, expresion):
return Just([self.exp.sustituir(var, expresion)])

Estos dos u
ltimos casos son an
alogos al anterior: la implementaci
on no hace m
as que llamar recursivamente a las funciones
apropiadas en la subexpresi
on y construir a partir de dichos resultados los datos que le fueron pedidos.
Con esta u
ltima clase disponemos ya de los terminos b
asicos que constituyen al tipo parametrico MaybeT. Sin embargo,
para su uso posterior ser
a conveniente declarar algunos terminos adicionales que faciliten su utilizaci
on.

3.5.

Definici
on de un t
ermino derivado simple

A continuaci
on nos concierne la declaraci
on de la expresi
on isNothing(E) que reduce a true si E es Nothing, o a false si
E es Just J. Veamos su implementaci
on:

Castillo, Martnez, Sainz-Tr


apaga

Pagina 22 de 30

class IsNothing(Expresion):
@classmethod
def sintaxis(cls):
return makeSintaxis(isNothing(, Exp, ))
def

init (self, toks):


self.exp = toks[0]

def

str (self):
return isNothing( %s) % self.exp

def reducir(self):
e = self.exp.reducir()
if isinstance(e,Nothing):
return Verdadero([])
else:
return Falso([])
def sustituir(self, var, expresion):
return IsNothing([self.exp.sustituir(var, expresion)])

Hasta este punto las definiciones son an


alogas a las vistas anteriormente. Sin embargo, la implementaci
on del tipado es
m
as novedosa:
def tipar(self, namespace):
st = self.exp.tipar(namespace)
if isinstance(st, TipoMaybe):
return Boolean([])
else:
raise TypeException(Tipo del T
ermino: %s \n +
El tipo del t
ermino debe ser Maybe(T). % st)

Observando la l
ogica del c
odigo, vemos que lo que hace es tipar el subtermino (es decir, si estamos lidiando con isNothing(E), obtiene el tipo de E) y a continuaci
on se fija si dicho tipo es realmente Maybe, verificando si es una instancia de
TipoMaybe. En caso afirmativo, el tipo de la expresi
on isNothing ser
a Boolean, clase de la que se devuelve una instancia.
De otro modo, se enva una TypeException indicando de forma informativa el error que se produjo, cual era el tipo esperado
y cual el que se recibi
o.

3.6.

Definici
on de un t
ermino derivado complejo

Como u
ltima declaraci
on analizaremos la implementaci
on de CaseMaybe, el observador en base a constructores de las
instancias de M aybe < T >.
class CaseMaybe(Expresion):
@classmethod
def sintaxis(cls):
return makeSintaxis(caseMaybe(, TipoExp, ), Exp, ; of nothing -> , Exp, ; just(J) -> , Exp)
def

init (self, toks):


self.tipo, self.exp, self.resNothing, self.resJust = toks

def

str (self):
return caseMaybe( %s) %s; of nothing -> %s; just(J) -> %s % \
(self.tipo, self.exp, self.resNothing, self.resJust)

Hasta este punto no se observan diferencias significativas. Es de notar que para simplificar el ejemplo se utiliz
o el nombre

Castillo, Martnez, Sainz-Tr


apaga

Pagina 23 de 30

fijo Jpara la variable del case.


def reducir(self):
expR = self.exp.reducir()
if isinstance(expR, Nothing):
return self.resNothing.reducir()
else:
return self.resJust.sustituir(J, expR.exp).reducir()

La primera diferencia que se observa entre esta extensi


on y la anterior se da en el caso de la reducci
on: en este caso, es
necesario para reducir exitosamente ligar la variable J a la expresi
on asociada. Esto es precisamente lo que hace el c
odigo
si detecta que la expresi
on interna (self.exp) es una instancia de Just.
def tipar(self, namespace):
maybet = self.exp.tipar(namespace)
trn = self.resNothing.tipar(namespace)
ns nuevo = namespace.copy()
ns nuevo[J] = self.tipo
trj = self.resJust.tipar(ns nuevo)
if isinstance(maybet, TipoMaybe) and trn == trj:
return trn
else:
raise TypeException((Tipo del T
ermino: %s \n +
Tipo del bloque Case Nothing: %s \n +
Tipo del bloque Case Just: %s \n +
El tipo de ambos casos debe ser compatible, y el tipo del t
ermino deb
a
ser Maybe(T).)'
(maybet, trn, trj))

La implementaci
on de la regla de tipado es similar a la que vimos en isNothing, aunque el chequeo a realizar es m
as
complejo (ya que deben asegurarse m
as condiciones). En este caso, se verifica que ambas ramasdel case tengan el mismo
tipo despues de ligar la variable J en el caso de Just, as como que self.exp tenga el tipo apropiado seg
un la declaraci
on del
case.
Una peculiaridad es el uso del namespace: n
otese que a diferencia de los casos anteriores, el contenido del mismo se
modifica. El namespace es un diccionario nativo de Python, que mapea strings a instancias de subclases de Tipo. Dado
que los diccionarios (al igual que pr
acticamente todo en Python) se pasan por referencia, es necesario copiar el namespace
explcitamente antes de realizar la modificaci
on del mismo ya que de otro modo se corre el riesgo de contaminar el namespace
de otras expresiones que compartan la misma instancia del diccionario.
def sustituir(self, var, expresion):
sMaybe = self.exp.sustituir(var, expresion)
sresNothing = self.resNothing.sustituir(var, expresion)
if var != J:
sresJust = self.resJust.sustituir(var, expresion)
else:
sresJust = self.resJust
return CaseMaybe([self.tipo, sMaybe, sresNothing, sresJust])

Por u
ltimo, el mecanismo de sustituci
on tambien es m
as complejo: en este caso, y como hay una variable ligada por esta
expresi
on, debe asegurarse de que no se realice una sustituci
on de la misma por pedido de una expresi
on de nivel m
as alto.
En este punto se establece el scope de la variable J, y se determina que su valor dentro del bloque correspondiente

Castillo, Martnez, Sainz-Tr


apaga

Pagina 24 de 30

del case ser


a establecido por self.reducir() y no por una sustituci
on anterior. As, frente a un pedido de sustituci
on, se
reemplazar
a cualquier variable menos J, que es local puesto que se define a nivel del Case.

3.7.

Creaci
on de la extensi
on

Finalmente, el u
nico punto pendiente es la creaci
on de la extensi
on propiamente dicha. El c
odigo es autoexplicativo: no
hay m
as que instanciar la clase Extension con una etiqueta apropiada.
######################################
# Armado de la nueva extensi
on
#
######################################
extensionMaybe = Extension(Maybe, expresiones=[Just, Nothing, IsNothing, CaseMaybe], tipos=[TipoMaybe])

Por u
ltimo, para que la extensi
on sea detectada por los aplicativos (tanto de consola como la interfaz gr
afica, es necesario
agregarla a la lista extensiones en registro.py. Esta lista es consultada por las aplicaciones para conocer las extensiones
que est
an disponibles.

Castillo, Martnez, Sainz-Tr


apaga

Parte 4

Extensiones
Los siguientes son los tipos y expresiones definidos por nosotros a modo de librera.

4.1.

Tipos

Boolean
Natural
Funci
on ( )
Registro
Lista

Arbol
Binario
Maybe
Tupla (Par ordenado)

4.2.

Expresiones

Booleanos:
True
False
if M then P else Q
Naturales:
zero
succ(M)
pred(M)
isZero(M)
Funciones:
Variables
X : T.M
Aplicaci
on (M N)
Registros:
construcci
on de registros
proyecci
on de registros
Listas:
Lista vaca
agregar elemento adelante (add(E,L))
case para listas (esquema para pattern matching)

Pagina 25 de 30

Castillo, Martnez, Sainz-Tr


apaga

Arboles binarios:
nil
constructor de a
rbol binario (bin(M,N,O))
case para arboles
Maybe
Nothing
Just
isNothing
case para Maybe
Tuplas
constructor de tupla
proyectores

Pagina 26 de 30

Castillo, Martnez, Sainz-Tr


apaga

Pagina 27 de 30

Parte 5

Posibles extensiones al trabajo


5.1.

Subtipado

Una ampliaci
on posible para el trabajo sera la incorporaci
on de reglas de subtipado. Esto es factible dentro del esquema
propuesto, y la forma simple de hacerlo sera sobrecargar el operador < para los tipos. De este modo, en vez de preguntar
si un tipo es igual a otro, se pregunta por menor o igual al momento de realizar los chequeos de tipos.
El siguiente c
odigo implementa la extensi
on de registros:

class TypeReg(Type):
"""
El tipo registro estara compuestos por etiquetas con tipos asociados.
"""
def init (self, tok ):
i =0
ids = {}
while(i < len(tok)):
ids[tok[i]] = tok[i+1]
i =i +2
self.ids = ids
"""
La igualdad de un tipo, con un tipo registro se da si en principio es un
registro y sus etiquetas coinciden en todos los tipos con los del otro tipo registo.
"""
def eq (self, otro):
if isinstance(otro, TypeReg):
res = True
for each in self.ids:
res = res and each in otro.ids and self.ids[each] == otro.ids[each]
if(not res):
return res
return len(self.ids) == len(otro.ids)
else:
return False
@classmethod
def sintaxis(cls):
campo = makeSintaxis(Id, :, TypeExp)
listaCampos = Optional(campo + ZeroOrMore(makeSintaxis(",", campo)))

Castillo, Martnez, Sainz-Tr


apaga

Pagina 28 de 30

reg = makeSintaxis({, listaCampos,})


return reg
def

str (self):
s = {
primero = True
for each in self.ids:
if primero:
primero = False
s+= str(each)+:+str(self.ids[each])
else:
s+=,+str(each)+:+str(self.ids[each])
s += }
return s

En el caso de los registros, tenemos reglas de subtipado a lo ancho y a lo largo, que podemos escribir como:

{Li |1 i n} {kj |1 j m}, kj = li Sj <: Ti


{kj : Sj |1 j m} <: {li : Ti |1 i n}
Este comportamiento puede agregarse a la extensi
on typeReg de esta forma:

def le (self, other):


""" determina si un tipo registro es subtipo de otro """
# other tiene que ser un registro
if(isinstance(other,TypeReg)):
res = True
#tiene que tener todo lo que tiene el otro
for each in other.ids:
res = res and (each in self.ids)
if not res: return False
#cada label compartida tiene que ser subtipo
for each in other.ids:
res = res and (self.ids[each] < other.ids[each])
return res

El principal conflicto con esto es que habra que modificar el c


odigo de las extensiones ya implementadas. Esto es necesario
por un lado para que utilicen subtipado seg
un corresponda, y por otro lado porque en algunos casos hay expresiones que
deben tipar y que en el modelo utilizado para este trabajo no reducen (y no son valores).
Por ejemplo, pred(true) tipa Nat, ya que Bool < Nat, pero no tiene definida ninguna regla de reducci
on. Esto se podra
resolver o bien cambiando el metodo reducir de pred, o agregando un metodo a Bool para determinar dado un valor de tipo
Bool que instancia de Nat representa. Asimismo sera necesario construir estas reglas de coercion para varios de los tipos
b
asicos.

Castillo, Martnez, Sainz-Tr


apaga

5.2.

Pagina 29 de 30

Inferencia de tipos y otras alternativas

Durante la cursada vimos como implementar el algoritmo de inferencia de tipos para el c


alculo lambda (que adem
as
implemetamos en una clase de laboratior). Por esta raz
on, decidimos usar tipado simple y no inferencia de tipos para
enfocarnos en el aspecto central de nuestro trabajo que era la simplicidad de extensi
on.
Del mismo modo, podra construirse como extensi
on futura el agregado de polimorfismo, as como tambien junto con
este considerar el desarrollo de clases de tipos (similares a las de Haskell, donde tenemos Eq para denotar que los tipos tienen
comparaci
on por igual, o Show para denotar a los tipos que tienen una funcion show para ser mostrados por pantalla).

Castillo, Martnez, Sainz-Tr


apaga

Pagina 30 de 30

Parte 6

Conclusi
on
Como conclusi
on final podemos enumerar una serie de conceptos que resultaron de la realizaci
on de este trabajo pr
actico.
En primer lugar, y como se explic
o en la introducci
on, la idea de este trabajo era poder lograr un interprete de lambda
c
alculo que no s
olo funcionara de manera correcta, sino que tambien pudiese ser extendido para incluir nuevos tipos y
expresiones de forma sencilla.
Consideramos que este objetivo se cumpli
o, ya que pudimos elaborar una manera est
andar de introducir nuevas extensiones al interprete. Adem
as, consideramos que hallamos un equilibrio razonable entre la sencillez de extensi
on y la flexibilidad
que se permite al agregar nuevos terminos al lenguaje. No se utilizaron conveciones extremadamente fuertes que podran
haber causado limitaciones poco pr
acticas para extender el lenguaje de forma extravagante. A su vez, la inclusi
on del tutorial
debera hacer que la incorporaci
on de una nueva extensi
on sea un procedimiento sencillo incluso para aquellas personas que
no est
an familiarizadas con el trabajo ni con el lenguaje Python.
Por otro lado creemos que el enfoque del trabajo se orient
o a uno de los temas m
as importantes de la cursada, y que se
logr
o no s
olo combinarlo con programaci
on orientada a objetos, sino tambien encontrar una forma din
amica de resolverlo. Si
bien es cierto que durante la cursada se implementaron cuestiones relacionadas al lambda c
aculo, la visi
on de este trabajo es
m
as compacta y abarca las cuestiones principales del tema (como ser el manejo de tipado, sintaxis, reducci
on y extensiones
al c
alculo). Adem
as, los trabajos pr
acticos llevados a cabo durante la cursada tuvieron enfoques menos globales que este,
que nos permiti
o construir un interprete de un lenguaje de programaci
on de principio a fin.
Como se
nalamos en el apartado anterior, nos hubiese gustado tambien implementar otras cuestiones como es el caso de
las reglas de subtipado. Sin embargo, se dejaron las puertas abiertas a dicha extensi
on como se coment
o anteriormente.
Consideramos que como punto final a la materia, la realizaci
on de un trabajo pr
actico constituy
o una soluci
on din
amica e
interactiva, y nos permiti
o utilizar lo aprendido para construir una herramienta completa, que podra tener posibilidades de
uso futuro dentro de la materia. Futuros estudiantes pueden examinar el c
odigo entregado para comprender el funcionamiento
de un interprete, y servirse de la gran cantidad de extensiones propuestas como referencia para implementar las suyas.

Anda mungkin juga menyukai