interprete calculo lambda

Upload: carlos-antonio-lazaro-mauricio

Post on 19-Feb-2018

228 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/23/2019 Interprete Calculo Lambda

    1/33

    Trabajo Practico Final

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

    Integrante LU Correo electronico

    Castillo, Gonzalo 164/06 gonzalocastillo [email protected]

    Martnez, Federico 17/06 [email protected]

    Sainz-Trapaga, Gonzalo 454/06 [email protected]

    En el siguiente trabajo se presenta la implementacion de un interprete extensible para Calculo Lambda tipado. A lo largodel mismo se desarrollan las principales problematicas de implementacion, se explica como realizar nuevas extensiones alcalculo y se detallan posibles extensiones al trabajo.

    Facultad de Ciencias Exactas y Naturales

    Universidad de Buenos Aires

    Ciudad Universitaria - (Pabellon I/Planta Baja)

    Intendente Guiraldes 2160 - C1428EGA

    Ciudad Autonoma de Buenos Aires - Rep. Argentina

    Tel/Fax: (54 11) 4576-3359http://www.fcen.uba.ar

  • 7/23/2019 Interprete Calculo Lambda

    2/33

    Indice general

    1. Introduccion 1

    1.1. Introduccion teorica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

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

    1.3. Organizacion del informe. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

    2. Detalles de implementacion 2

    2.1. Lenguaje de programacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

    2.2. Definicion de extensiones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

    2.2.1. Creacion de Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

    2.2.2. Creacion de Expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

    2.2.3. Construccion de extensiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

    2.3. Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

    2.3.1. Mecanismo de analisis sintactico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

    2.3.2. Definicion de reglas sintacticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

    2.4. Tipado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

    2.5. Semantica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

    2.6. Tipos y terminos basicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

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

    2.6.2. Abstracciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

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

    2.6.4. Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

    2.6.5. Aplicacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

    2.6.6. Nat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

    2.6.7. Zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

    2.6.8. Succ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

  • 7/23/2019 Interprete Calculo Lambda

    3/33

    2.6.9. Pred . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

    2.6.10. isZero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

    3. Tutorial 18

    3.1. La extension Maybe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

    3.2. Codigo boilerplate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

    3.3. Creando un nuevo tipo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

    3.4. Definicion de expresiones basicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

    3.5. Definicion de un termino derivado simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

    3.6. Definicion de un termino derivado complejo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

    3.7. Creacion de la extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 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. Conclusion 30

  • 7/23/2019 Interprete Calculo Lambda

    4/33

    Castillo, Martnez, Sainz-Trapaga Pagina 1 de30

    Parte 1

    Introduccion

    1.1. Introduccion teorica

    El Calculo Lambda es un modelo de computacion basado en funciones. Por tratarse de un modelo computacionalmentecompleto y riguroso en su formulacion, se utiliza con frecuencia como herramienta para el estudio de lenguajes de programa-cion y sus propiedades, as como lenguaje de referencia para la definicion de semantica en otros lenguajes de programacion.

    La version del Calculo Lambda desarrollada en este trabajo es el Calculo Lambda Tipado (A. Church, 19401).

    1.2. Objetivos del trabajo

    El trabajo propuesto consiste en el desarrollo de un interprete para Calculo Lambda Tipado, con el foco fijado en lafacilidad de extension del mismo. Durante el cuatrimestre se utilizo una definicion basica del Calculo que se extendio pro-gresivamente agregando nuevas funcionalidades propias de los distintos paradigmas de programacion. La idea del interpretedesarrollado era adaptarse al desarrollo propuesto en la materia, de modo que agregar nuevas extensiones al calculo sea unatarea tan simple como sea posible.

    La facilidad de extension se da a traves del uso del paradigma orientado a objetos y el uso intensivo de herencia comoherramienta de reuso de codigo, minimizando as la cantidad de lneas necesarias para la creacion de una extension. Dadaesta facilidad, debera ser factible incorporar al trabajo como complemento de la materia por la capacidad que provee depermitir a los alumnos interactuar de forma mas directa con el modelo.

    Finalmente, ademas del sistema basico y facilmente extensible, se incluyen ademas con el trabajo la mayora de lasextensiones que fueron propuestas en clase durante el cuatrimestre, y documentacion suficiente como para que agregarnuevas extensiones sea una tarea accesible.

    1.3. Organizacion del informe

    El presente informe se organiza de la siguiente manera:

    En el apartado2 se explican los detalles concernientes a la implementacion del interprete, as como las decisiones dediseno que fueron tomadas a la hora de desarrollar.

    En 3 se detalla paso a paso la construccion de una nueva extension, con el objetivo de familiarizar al lector con elproblema y la solucion como la proponemos.

    En4 se enumeran las extensiones ya implementadas por nosotros.

    Por ultimo, en5 comentamos posibles extensiones o mejoras que podran realizarse al traba jo.

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

  • 7/23/2019 Interprete Calculo Lambda

    5/33

    Castillo, Martnez, Sainz-Trapaga Pagina 2 de30

    Parte 2

    Detalles de implementacion

    2.1. Lenguaje de programacion

    Para la implementacion del interprete utilizamos el lenguaje de programacion Python, en parte por tratarse de unlenguaje con el que estamos acostumbrados a trabajar, pero ademas porque consideramos que su sintaxis sencilla y limpiaes adecuada para facilitar la construccion posterior de extensiones, aun por personas que no esten familiarizadas con ellenguaje.

    2.2. Definicion de extensiones

    Conceptualmente, el interprete concibe a un lengua je como una coleccion de extensiones. Una extension consta de un

    nombre apropiado para identificarla, una coleccion de tipos y una coleccion de terminos, as como las reglas necesarias paradarles tipado, sintaxis y semantica a las expresiones del lenguaje extendido.

    Esta idea reproduce la aproximacion ofrecida en clase, en la que se parte de un c alculo basico con algunos elementosesenciales, y sobre el que se van construyendo nuevas estructuras.

    Como dijimos, la caracterstica principal de esta implementacion es que permite agregar extensiones (es decir, tipos yexpresiones). As, en lo que respecta al codigo, crear nuevas extensiones consiste en subclasear dos clases llamadas Expresiony Tipo que residen en expresion.py.

    2.2.1. Creacion 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 partirde estos construye la instancia. En general, al momento de ser procesados por este constructor, lostokens ya fueronprocesados y son objetos que representan a su vez a otros tipos (analogo al funcionamiento de unfold), y son necesariospara la creacion de tipos recursivos.

    sintaxis(cls): un classmethod o metodo est atico que define la sintaxis con la que se va a parsear una expresion detipo1.

    eq (self,other): la comparacion por igualdad entre tipos, que debe funcionar como la relacion unifica. Por defectola clase padre Tipo considera que un tipo unifica con otro si son de la misma clase, por lo cual si este comportamientoes el esperado no es necesario definirlo (por ejemplo, Nat unifica con Nat, pero para tipos recursivos podra no sersuficiente esta definicion).

    1Nota: No confundir expresion de tipo con expresiones tipadas del calculo. La clase hija de Tipo define la sintaxis que utiliza el

    lenguaje para referirse al tip o propiamente dicho, por ejemplo, en las declaraciones de funciones. La sintaxis de los terminos que tipan

    a este tipo es competencia de las clases hijas de expresion, que se detallan mas adelante

  • 7/23/2019 Interprete Calculo Lambda

    6/33

    Castillo, Martnez, Sainz-Trapaga Pagina 3 de30

    str (self): (optativo) el equivalente a toStringen otros lenguajes, que se utiliza para imprimir por pantalla a lasinstancias de la clase.

    2.2.2. Creacion de Expresiones

    Para crear una nueva expresion valida dentro del lenguaje, se debe heredar de la clase Expresion y asegurarse deimplementar los siguientes metodos:

    init (self, tok): el constructor, que construye una instancia de la expresion a partir de una lista de tokens (ver2.3).

    sintaxis(cls): analogo a la extension de tipos, este metodo estatico define la sintaxis de una expresion de esta clase(ver 2.3).

    reducir(self): implementa la semantica de la expresion (ver2.5).

    tipar(self, namespace): implementa las reglas de tipado de la expresion (ver2.4).

    sustituir(self, var, expresion): implementa las reglas de sustitucion para las instancias, dondevares el nombre deuna variable a ser reemplazada por expresion. Es aqu donde se determina, entre otras cosas, elscopede las variables.

    str (self): (optativo) el equivalente a toStringen otros lenguajes, que se utiliza para imprimir por pantalla a lasinstancias de la clase.

    2.2.3. Construccion de extensiones

    Finalmente, una extension se modela como una instancia de la clase Extension, 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, puedeconstruirse un lenguaje a partir de una serie de extensiones que se cargan o descargan dinamicamente. El procedimiento sedetalla con mayor precision en3.

    2.3. Sintaxis

    2.3.1. Mecanismo de analisis sintactico

    Uno de los problemas principales a resolver para permitir la posterior definicion de extensiones era como facilitar ladefinicion de la sintaxis de los nuevos terminos sin obligar al usuario a interactuar de forma directa con elparser utilizado.El desafo consistio ademas en dar una forma sencilla de definir la sintaxis, pero sin imponer restricciones innecesarias a lacomplejidad de las extensiones que p odran definirse.

    Las herramientas que conocemos que permiten definir sintaxis y semantica de forma combinada y sin demasiado codigode por medio son las de Gramaticas de Atributos y Traduccion Dirigida por Sintaxis. Sin embargo, consideramos que lidiar

    con las particularidades de las gramaticas libres de contexto era algo a evitar, por lo que buscamos una alternativa massimple.

    La solucion elegida es intermedia. Por un lado, se logro que definir la sintaxis (y su correspondiente semantica) searelativamente sencillo, abstrayendo la mayor parte del codigo comun, y manteniendo una sintaxis medianamente simple. Porotra parte, varios de loshelpersintroducidos para simplificar la creacion de extensiones pueden omitirse para as tener masflexibilidad a la hora de trabajar. Esto se debe a que dichos helpersse definen en su mayora como funciones auxiliares queestan 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 implementacion de la libreraPyParsingpor el uso excelente que hace de la sobrecarga de operadores y de las capacidades de alto nivel de Python parapermitir la definicion amigable de reglas gramaticales utilizando Python de forma directa, sin recurrir a definicies externasen otros lenguajes.

    El parser utiliza backtracking, porque de otro modo sera imposible permitir anadir de forma simple nuevas reglassintacticas que podran introducir ambiguedades en parsers recursivos. Este problema proviene del hecho de que los parsersrecursivos descendentes son una familia similar a los LL(1), y por tanto lidian de forma limitada con los posibles prefijos de

  • 7/23/2019 Interprete Calculo Lambda

    7/33

    Castillo, Martnez, Sainz-Trapaga Pagina 4 de30

    una definicion 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 recursion a izquierda en la definicion de reglas. Esta es una limitacion propia delmecanismo de parsing que nos obligo a realizar algunas modificaciones en el lenguaje aceptado por el interprete.

    As, p or ejemplo, para el caso de la aplicacion, la produccion:

    Exp Exp Exp

    no puede ser parseada por este procedimiento (dado que el programa entrara en un bucle infinito hasta terminar porstackoverflow. Por lo tanto, en su lugar proponemos:

    Exp (Exp Exp)

    La gramatica sigue siendo ambigua, pero al eliminar la recursion a izquierda mediante la introduccion de parentesis, elparser puede eliminar la ambiguedad utilizando alguna heurstica de decision (seafirst-match o longest-match, segun lo queuno considere mas conveniente). Esto elimina una preocupacion a la hora de definir nuevas extensiones.

    Por ultimo, es importante mencionar que las expresiones del lenguaje, a excepcion de los terminos de tipo y las variables,no deberan utilizar letras mayusculas ya que este criterio se utiliza para diferenciar entre s a estos diferentes elementos.

    2.3.2. Definicion de reglas sintacticas

    Como se menciono antes, es el metodo estatico sintaxis() para expresiones el que devuelve el lado derecho de unaproduccion que se utilizara al momento de parsear una expresion. Este lado derecho se asocia al no terminal Exp de lagramatica, que es el smbolo inicial que produce todos los terminos del lenguaje, y puede ser usado en la definicion de lasintaxis para referirse (recursivamente) a cualquier termino. Su analogo TipoExp caracteriza a las expresiones de tipos ypuede a su vez usarse en las definiciones de sintaxis.

    Para la definicion de la sintaxis se pueden utilizar directamente las distintas clases que provee PyParsing, y sobre lasque hay excelente documentacion en el sitio web correspondiente. Por ejemplo, la sintaxis delif 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

    Notese que la sintaxis es simple, utilizando el operando de suma para la concatenacion y las referencias a Exp cuandoes necesario indicar que en ese lugar aparece una expresion arbitraria. La lista de tokens que se construye a partir de esa

    expresion es la que luego recibe el constructor de la expresion para instanciar un objeto.

    El metodo suppress() elimina el token despues de hallarlo porque no resulta de interes para su utilizacion posterior(puesto que no contiene informacion). As, se eliminan todos los strings fijos de la expresion conservando as solo lassubexpresiones, que son las que interesan al momento de construir una instancia del objeto correspondiente a la expresionif. Notese que no es necesario utilizarsuppress(), pero de no hacerlo se deberan ignorar los tokensen el constructor de laexpresion.

    Sin embargo, para sintaxis simples puede usarse elhelperexpresion.makeSintaxis(*args), que recibe como parametroslos componentes sintacticos para armar la produccion. Asi por ejemplo, para definir la sintaxis del if:

    makeSintaxis(if,Exp,then,Exp,else,Exp)

    La funcion makeSintaxis transforma las cadenas de letras en Keywords, las cadenas que contengan smbolos en Literals, ylas Exp (o cualquier otra instancia deparseElement) las mantiene, y devuelve la expresion que resulta de la concatenacion

  • 7/23/2019 Interprete Calculo Lambda

    8/33

    Castillo, Martnez, Sainz-Trapaga Pagina 5 de30

    de todas ellas. Si bien sintaxis mas complejas (como el caso de los registros con campos nombrados) no pueden definirse conmakeSintaxis, por lo que sera necesario utilizar el metodo anterior, mas extenso pero mas flexible.

    Como se dijo anteriormente, al parsear una expresion segun esta sintaxis, se pasan lostokensal constructor para construirel objeto apropiado. Los tokens son todos las instancias de parseElement que no tengan suppressactivado. En el caso delif, los tokens son las tres instancias de Exp. Notar que al constructor del if llegara 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 subclasedeExpresion).

    2.4. Tipado

    Dado que implementamos un lambda calculo tipado, un elemento fundamental en la definicion de nuevas expresiones sonlas reglas de tipado. El metodo debe devolver una instancia de alguna subclase de Tipo indicando el tipo correspondiente odebe 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 Tipoimplementen un eq adecuado a su semantica.

    La funcion tipar recibe ademas como parametro el contexto de tipado, que funciona como diccionario de nombre devariable (string) a su tipo.

    2.5. Semantica

    La semantica en nuestra implemetancion esta dada por el metodo reducir. Esta reduccion es del tipo big-step, es decirsi un termino tipa, una llamada a reducir debe devolver el valor al que reduce.

    A la hora de definir la semantica, puede asumirse como precondicion que el termino tipa, ya que el interprete chequeapreviamente que la expresion tipe antes de intentar reducirla. Es importante asegurarse de que si el termino tipa, la

    reduccion no deberia fallar. De esta manera el metodo reducir debe devolver la instancia de expresion que resulta de reducircompletamente al termino.

    2.6. Tipos y terminos basicos

    En esta seccion presentaremos los tipos basicos vistos en clase junto con su implementacion para nuestro lenguaje.Consideraremos como tipos basicos 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 exactamentede la misma manera en que se definira cualquier extension. Sin embargo, por su naturaleza esencial, son requeridos por casitodas las demas extensiones y por tanto son de interes especial.

    2.6.1. Boolean, true y false

    Terminos

    M ::=true|false

  • 7/23/2019 Interprete Calculo Lambda

    9/33

    Castillo, Martnez, Sainz-Trapaga Pagina 6 de30

    Reglas de tipado

    true: Bool

    f alse: Bool

    Semantica

    Las expresiones true y false son valores, no reducen.

    Implementacion

    Esta implementacion, por su sencillez, hace uso de otros dos helpersapropiados para la construccion de tipos basicos(no parametricos) y atomos de algun tipo particular. Se trata de las funciones simpleTypeFactory (que crea una claseapropiada a partir de la sintaxis del termino de tipo) y atomoFactory(que crea una clase hija de Expresion a partir de susintaxis 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 repeticioninnecesaria de codigo en los lugares donde no es necesaria la flexibilidad.

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

    2.6.2. Abstracciones

    Terminos

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

    Reglas de tipado

    , X : M :

    X :.M :

    Semantica

    Las abstracciones son valores, no reducen.

  • 7/23/2019 Interprete Calculo Lambda

    10/33

    Castillo, Martnez, Sainz-Trapaga Pagina 7 de30

    Implementacion

    class Func(Tipo):

    def init (self,tok):"""

    Define para el tipo funcion el dominio y la imagen.

    """

    dom, img = tokself.dominio = domself.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

    @classmethoddefsintaxis(cls):

    Abs = makeSintaxis((, TipoExp, -> , TipoExp, ) )return Abs

    def str (self):s1 =str(self.dominio)s2 =str(self.imagen)ifself.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 = toksself.var = varself.tipoVar = tipoself.expresion = expresion

    defreducir(self):"""

    Una Abstraccion reduce a si misma, es un valor.

    """

    return self

    deftipar(self, namespace):"""

    gamma,{X:alpha} | > M : beta----------------------------

    gamma | > \X:alpha.M : (alpha -> beta)"""

    nam2 = dict(namespace)

    nam2[self.var] = self.tipoVarreturn Func([self.tipoVar, self.expresion.tipar(nam2)])

  • 7/23/2019 Interprete Calculo Lambda

    11/33

    Castillo, Martnez, Sainz-Trapaga Pagina 8 de30

    defsustituir(self, var, expresion):"""

    \X:alpha.M {X \X:alpha.M\X:alpha.M {Y \X:alpha.(M {Y

  • 7/23/2019 Interprete Calculo Lambda

    12/33

    Castillo, Martnez, Sainz-Trapaga Pagina 9 de30

    Implementacion

    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 = toksself.guarda = guardaself.ramaTrue = ramaTrueself.ramaFalse = ramaFalse

    defreducir(self):"""

    Reduccion de la guarda a un valor. Luego dependiendo de dicho valor

    se reduce la rama verdadera o la falsa.

    """ifisinstance(self.guarda.reducir(), Verdadero):

    return self.ramaTrue.reducir()else:

    return self.ramaFalse.reducir()

    deftipar(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 : Booleanif tipoGuarda == Boolean([]):

    # gamma | > RamaTrue : alpha, gamma | > RamaFalse : alphaif tipoRamaTrue == tipoRamaFalse:

    # gamma | > if Guarda then RamaTrue else RamaFalse : alphareturn tipoRamaTrue

    else:raise TypeException(Tipo rama true: %s \n % tipoRamaTrue + \

    Tipo rama false:%s \n % tipoRamaFalse + \No existe unificacion 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.)

    defsustituir(self, var, expresion):"""

    if M then N else O {X if M {X

  • 7/23/2019 Interprete Calculo Lambda

    13/33

    Castillo, Martnez, Sainz-Trapaga Pagina 10 de30

    # if M then N else O

    If = makeSintaxis(if , Exp,then, Exp,else, Exp)return If

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

    2.6.4. Variables

    Terminos

    es un conjunto infinito enumerable de variables, X ,

    M ::=...|X

    Reglas de tipado

    {X :}

    X :

    Semantica

    Las variables no reducen, tienen que ser sustitudas.

    Implementacion

    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]

    defreducir(self):"""

    Las variables reducen a si mismas, tiene que ser sustituidas.

    """

    return self

    deftipar(self, namespace):"""

    {X : alpha} pertenece a gamma----------------------------

    gamma | > X : alpha

    """if not (self.id in namespace):

    for each in namespace:

  • 7/23/2019 Interprete Calculo Lambda

    14/33

    Castillo, Martnez, Sainz-Trapaga Pagina 11 de30

    print each, namespace[each], each. classraise TypeException((No es posible determinar el tipo de la variable %s a + \

    partir del contexto: %s.) % (self.id, namespace))return namespace[self.id]

    defsustituir(self, var, expresion):

    """X {X TX {Y X s i X ! = Y"""

    ifself.id== var:return expresion

    else:return self

    @classmethoddefsintaxis(cls):

    Id = Regex([A-Z][a-zA-Z]*)return Id

    def str (self):return self.id

    2.6.5. Aplicacion

    Terminos

    M ::=...|M N

    Reglas de tipado

    M : , N :

    M N :

    Semantica

    M M

    M N M N

    N N

    V N V N

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

  • 7/23/2019 Interprete Calculo Lambda

    15/33

    Castillo, Martnez, Sainz-Trapaga Pagina 12 de30

    Implementacion

    class Aplicacion(Expresion):

    def init (self, toks):"""

    Una aplicacion esta compuesta por una funcion aplicadora y

    un parametro.

    """

    aplicador, parametro = toksself.aplicador = aplicadorself.parametro = parametro

    defreducir(self):"""

    Se reduce la funcion aplicadora y el parametro, luego:

    (\X:alpha.M V) --> M {X M: (alpha -> beta), gamma | > N: alpha------------------------------------------------

    gamma | > (M N) : beta"""

    x = self.aplicador.tipar(namespace)z = self.parametro.tipar(namespace)

    ifisinstance(x, Func):ifx.dominio == z:

    return x.imagenelse:

    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)

    defsustituir(self, var, expresion):"""

    (M N) {X (M {X

  • 7/23/2019 Interprete Calculo Lambda

    16/33

    Castillo, Martnez, Sainz-Trapaga Pagina 13 de30

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

    2.6.6. Nat

    Implementacion

    Nat = simpleTypeFactory(Nat)

    2.6.7. Zero

    Terminos

    M ::=...|zero

    Reglas de tipado

    zero: N at

    Semantica

    zero no reduce, es un valor.

    Implementacion

    Zero = atomoFactory(zero, Nat)

    2.6.8. Succ

    Terminos

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

  • 7/23/2019 Interprete Calculo Lambda

    17/33

    Castillo, Martnez, Sainz-Trapaga Pagina 14 de30

    Reglas de tipado

    M :N at

    succ(M) :N at

    Semantica

    M M

    succ(M) succ(M)

    Implementacion

    class Succ(Expresion):

    def init (self, toks):"""

    Define para estructura succ la expresion que contiene.

    """

    self.termino = toks[0]

    defreducir(self):"""

    Reducir succ(E) corresponde a reducir E."""

    terminoRed = self.termino.reducir()return Succ([terminoRed])

    deftipar(self, namespace):"""

    gamma | > E : Nat-----------------

    gamma | > succ(E) : Nat"""

    ifself.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))

    defsustituir(self, var, expresion):"""

    succ(E) {X succ(E {X

  • 7/23/2019 Interprete Calculo Lambda

    18/33

    Castillo, Martnez, Sainz-Trapaga Pagina 15 de30

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

    2.6.9. Pred

    Terminos

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

    Reglas de tipado

    M :N at

    pred(M) :N at

    Semantica

    M M

    pred(M) pred(M)

    pred(succ(M)) M

    pred(zero) zero

    Implementacion

    class Pred(Expresion):

    def init (self, toks):"""

    Define para estructura succ la expresion que contiene.

    """

    self.termino = toks[0]

    defreducir(self):"""

    Se reduce primero el la expresion que contiene pred, luego:

    pred(zero) --> zeropred(succ(v)) --> v

    """

  • 7/23/2019 Interprete Calculo Lambda

    19/33

    Castillo, Martnez, Sainz-Trapaga Pagina 16 de30

    termino = self.termino.reducir()ifisinstance(termino, Zero):

    return terminoelse:

    return termino.termino

    deftipar(self, namespace):"""

    gamma | > E : Nat-----------------

    gamma | > pred(E) : Nat"""

    ifself.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))

    defsustituir(self, var, expresion):"""

    pred(E) {X pred(E {X

  • 7/23/2019 Interprete Calculo Lambda

    20/33

    Castillo, Martnez, Sainz-Trapaga Pagina 17 de30

    isZero(succ(M)) false

    isZero(zero) true

    Implementacion

    class IsZero(Expresion):

    def init (self, toks):"""

    Se define para la estructura isZero la expresion que contiene.

    """self.termino = toks[0]

    defreducir(self):"""

    Se reduce primero la expresion que contiene isZero, luego:

    isZero(zero) --> true

    isZero(succ(v)) --> false

    """

    termino = self.termino.reducir()ifisinstance(termino, Zero):

    return Verdadero([])else:

    return Falso([])

    deftipar(self, namespace):"""

    gamma | > E : Nat----------------

    gamma | > isZero(E): Boolean"""

    ifself.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))

    defsustituir(self, var, expresion):"""

    isZero(E) {X isZero(E {X

  • 7/23/2019 Interprete Calculo Lambda

    21/33

    Castillo, Martnez, Sainz-Trapaga Pagina 18 de30

    Parte 3

    Tutorial

    3.1. La extension Maybe

    En este tutorial vamos a realizar paso por paso la extension que llamamos Maybe, y que nos permite definir un tipoparametrico Maybe < T >que tiene dos constructores: Nothing < T >y Just J(donde J es un termino de tipo T).

    Para construir la extension, tenemos que:

    crear el tipo

    crear las expresiones basicas Nothing y Just

    crear una funcion simple: isNothing

    crear una funcion mas compleja: caseMaybe

    crear la extension propiamente dicha y registrarla con el interprete

    3.2. Codigo boilerplate

    Para crear la nueva extension creamos un nuevo archivo de texto vaco en la carpeta extensiones (idealmente conextension .py) y pegamos el siguiente codigo en el:

    #!/usr/bin/python

    # -*- coding: utf8 -*-

    from expresion import Expresion, Tipo, Exp, TipoExp, TypeExceptionfrom expresion import makeSintaxis

    from booleans import Booleanfrom lenguaje import Extension

    Como veran, se trata de una serie de imports de objetos que vamos a necesitar referenciar en nuestro codigo. Expresiony Tipo son las clases de las que vamos a heredar para construir los terminos y tipos de nuestra extension (que se construyea 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 unaexpresion cualquiera o n termino de tipo cualquiera. TypeException es la excepcion que debemos producir cuando hayaun error de tipos

    Finalmente, Boolean es la clase que corresponde al tipo homonimo (y por tanto vive en la extension correspondiente). Es

  • 7/23/2019 Interprete Calculo Lambda

    22/33

    Castillo, Martnez, Sainz-Trapaga Pagina 19 de30

    necesaria porque mas adelante vamos a necesitar indicarle al sistema de tipado que un termino es de tipo Boolean (adivinancual?), 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 tipoparametrico, y por lo tanto hay que definirlo a mano extendiendo directamente la clase Tipo. Comencemos entonces pordefinir la sintaxis:

    #######################################

    # Declaracion del nuevo tipo Maybe(T) #

    #######################################

    class TipoMaybe(Tipo):@classmethoddefsintaxis(cls):

    return makeSintaxis(Maybe(, TipoExp, ))

    Esta declaracion decorada (la lnea que comienza con @ se llama decorator en Python) crea un metodo estatico dela clase TipoMaybe (que luego se llama como TipoMaybe.sintaxis()). En este caso utilizamos el helper makeSintaxis paradecirle al interprete que un termino que describe al tipo TipoMaybe tiene la sintaxis Maybe(TipoExp), donde TipoExprepresenta a una expresion de tipo cualquiera (por ejemplo, Nat, Bool o incluso Maybe(Nat)!).

    La definicion sin makeSintaxis hubiera sido mas larga y difcil de leer(y ademas hubiera sido necesario importar Literaldesde 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 construccion es simple, unicamente se almacena como un atributo de instancia el primer elemento de la lista toks,que corresponde al primer y unico token que matchea la sintaxis del tipo (recordemos que como se utiliza suppress()implcitamente sobre los chunks Maybe( y ), estos no seran recibidos por el constructor). Sigamos:

    def eq (self, otro):return self. class == otro. class and \

    self.tipo == otro.tipo

    Un TipoMaybe < T > sera igual a otro si el segundo es un TipoMaybe (esa es la implementacion heredada de la claseTipo, y no sera necesario sobrecargarla si fuera esta la definicion), pero tambien si el tipo englobado por el Maybe esigual al otro. Recordemos que si bien se utiliza el operador de igualdad, la nocion asociada al mismo es la de unificacion.

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

    Finalmente, el ultimo metodo define la forma en que se convierte el objeto a una representacion en forma de string

    amigable para el usuario. En este caso (y en todos los demas), nos limitamos a reproducir la sintaxis.

    Con esto ya tenemos el nuevo tipo definido, y podemos dedicarnos a construir los terminos asociados al mismo.

  • 7/23/2019 Interprete Calculo Lambda

    23/33

    Castillo, Martnez, Sainz-Trapaga Pagina 20 de30

    3.4. Definicion de expresiones basicas

    A continuacion vamos a definir las dos expresiones basicas del tipo Maybe(T), empezando por Nothing (y esta vezheredando de Expresion en lugar de Tipo).

    ######################################

    # Declaracion de nuevas expresiones #

    ######################################

    class Nothing(Expresion):@classmethoddefsintaxis(cls):

    return makeSintaxis(nothing(, TipoExp, ))

    La definicion de sintaxis es analoga a la definicion de sintaxis en el termino de tipo. Hay dos particularidades para notaren esta definicion. La primera es que la expresion que definimos como nothing(T) consta de una variable de tipo(denotadapor TipoExp) que permite tipar la expresion. En segundo lugar, no hay que olvidar que los terminos no deben llevar

    mayusculas (ya que el parser asume que las cosas que comienzan por mayusculas dentro de una expresion son variables).Por esta razon, el atomo 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 funcion de conversion a string son exactamente iguales a las de la definicion del tipo y portanto no requieren explicacion adicional. Veamos ahora que ocurre con las funciones propias de la clase Expresion.

    defreducir(self):return self

    La funcion reducir() es responsable de producir un termino reducido (con semantica big-step) a partir de la expresionactual. Sin embargo, en el caso de Nothing y por tratarse de un valor, no hay que hacer ninguna reduccion y es suficientecon devolver una referencia al propio objeto que recibe el mensaje.

    deftipar(self, namespace):return TipoMaybe([self.tipo])

    La funcion tipar() se encarga de producir una instancia del tipo correspondiente a esta expresion. 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 deTypeMaybe < Nat >.

    Notese la peculiaridad de que TipoMaybe recibe una lista de tokens, y por lo tanto se debe pasar como parametro[self.tipo] (entre corchetes).

    defsustituir(self, var, expresion):return self

    Finalmente, el mecanismo de sustitucion, por tratarse de un atomo inmutable, se limita a devolver una referencia alpropio objeto sin sustituir nada (ya que no pueden aparecer variables dentro de esta expresion).

    Veamos ahora la definicion de Just J:

  • 7/23/2019 Interprete Calculo Lambda

    24/33

    Castillo, Martnez, Sainz-Trapaga Pagina 21 de30

    class Just(Expresion):@classmethoddefsintaxis(cls):

    return makeSintaxis(just(, Exp, ))

    En este caso la diferencia respecto de la definicion de nothing reside en que la subexpresion es un termino convencionaly no una declaracion de tipo. Esto es p osible puesto que a partir de dicho termino se p odra inferir su tipo y as establecerel tipado de esta expresion. Esto se refleja en la utilizacion de Exp en lugar de TipoExp dentro de la definicion de sintaxis.

    def init (self, toks):self.exp = toks[0]

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

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

    La definicion de reduccion se ajusta a lo definido por el Calculo Lambda: si MM luego Just(M)Just(M). Estoes precisamente lo que se establece aqu, con una llamada recursiva a reducir() de la expresion hija.

    deftipar(self, namespace):return TipoMaybe([self.exp.tipar(namespace)])

    defsustituir(self, var, expresion):return Just([self.exp.sustituir(var, expresion)])

    Estos dos ultimos casos son analogos al anterior: la implementacion no hace mas que llamar recursivamente a las funciones

    apropiadas en la subexpresion y construir a partir de dichos resultados los datos que le fueron pedidos.

    Con esta ultima clase disp onemos ya de los terminos basicos que constituyen al tipo parametrico MaybeT. Sin embargo,para su uso posterior sera conveniente declarar algunos terminos adicionales que faciliten su utilizacion.

    3.5. Definicion de un termino derivado simple

    A continuacion nos concierne la declaracion de la expresion isNothing(E) que reduce a true si E es Nothing, o a false siE es Just J. Veamos su implementacion:

  • 7/23/2019 Interprete Calculo Lambda

    25/33

    Castillo, Martnez, Sainz-Trapaga Pagina 22 de30

    class IsNothing(Expresion):@classmethoddefsintaxis(cls):

    return makeSintaxis(isNothing(, Exp, ))

    def init (self, toks):self.exp = toks[0]

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

    defreducir(self):e = self.exp.reducir()ifisinstance(e,Nothing):

    return Verdadero([])else:

    return Falso([])

    defsustituir(self, var, expresion):

    return IsNothing([self.exp.sustituir(var, expresion)])

    Hasta este punto las definiciones son analogas a las vistas anteriormente. Sin embargo, la implementacion del tipado esmas novedosa:

    deftipar(self, namespace):st = self.exp.tipar(namespace)ifisinstance(st, TipoMaybe):

    return Boolean([])else:

    raise TypeException(Tipo del Termino: %s \n +El tipo del termino debe ser Maybe(T). % st)

    Observando la logica del codigo, vemos que lo que hace es tipar el subtermino (es decir, si estamos lidiando con isNot-hing(E), obtiene el tipo de E) y a continuacion se fija si dicho tipo es realmente Maybe, verificando si es una instancia deTipoMaybe. En caso afirmativo, el tipo de la expresion isNothing sera 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 esperadoy cual el que se recibio.

    3.6. Definicion de un termino derivado complejo

    Como ultima declaracion analizaremos la implementacion de CaseMaybe, el observador en base a constructores de las

    instancias deMaybe < T >.

    class CaseMaybe(Expresion):@classmethoddefsintaxis(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 utilizo el nombre

  • 7/23/2019 Interprete Calculo Lambda

    26/33

    Castillo, Martnez, Sainz-Trapaga Pagina 23 de30

    fijo Jpara la variable del case.

    defreducir(self):expR = self.exp.reducir()ifisinstance(expR, Nothing):

    return self.resNothing.reducir()

    else:return self.resJust.sustituir(J, expR.exp).reducir()

    La primera diferencia que se observa entre esta extension y la anterior se da en el caso de la reduccion: en este caso, esnecesario para reducir exitosamente ligar la variable J a la expresion asociada. Esto es precisamente lo que hace el codigosi detecta que la expresion interna (self.exp) es una instancia de Just.

    deftipar(self, namespace):maybet = self.exp.tipar(namespace)trn = self.resNothing.tipar(namespace)

    ns nuevo = namespace.copy()

    ns nuevo[J] = self.tipotrj = self.resJust.tipar(ns nuevo)

    ifisinstance(maybet, TipoMaybe)and trn == trj:return trn

    else:raise TypeException((Tipo del Termino: %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 termino deba

    ser Maybe(T).)'

    (maybet, trn, trj))

    La implementacion de la regla de tipado es similar a la que vimos en isNothing, aunque el chequeo a realizar es m ascomplejo (ya que deben asegurarse mas condiciones). En este caso, se verifica que ambas ramasdel case tengan el mismotipo despues de ligar la variable J en el caso de Just, as como que self.exp tenga el tip o apropiado segun la declaracion delcase.

    Una peculiaridad es el uso del namespace: notese que a diferencia de los casos anteriores, el contenido del mismo semodifica. El namespace es un diccionario nativo de Python, que mapea strings a instancias de subclases de Tipo. Dadoque los diccionarios (al igual que practicamente todo en Python) se pasan por referencia, es necesario copiar el namespaceexplcitamente antes de realizar la modificacion del mismo ya que de otro modo se corre el riesgo de contaminar el namespacede otras expresiones que compartan la misma instancia del diccionario.

    defsustituir(self, var, expresion):sMaybe = self.exp.sustituir(var, expresion)sresNothing = self.resNothing.sustituir(var, expresion)

    ifvar != J:sresJust = self.resJust.sustituir(var, expresion)

    else:sresJust = self.resJust

    return CaseMaybe([self.tipo, sMaybe, sresNothing, sresJust])

    Por ultimo, el mecanismo de sustitucion tambien es mas complejo: en este caso, y como hay una variable ligada por estaexpresion, debe asegurarse de que no se realice una sustitucion de la misma por pedido de una expresion de nivel mas alto.

    En este punto se establece el scope de la variable J, y se determina que su valor dentro del bloque correspondiente

  • 7/23/2019 Interprete Calculo Lambda

    27/33

    Castillo, Martnez, Sainz-Trapaga Pagina 24 de30

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

    3.7. Creacion de la extension

    Finalmente, el unico punto pendiente es la creacion de la extension propiamente dicha. El codigo es autoexplicativo: nohay mas que instanciar la clase Extension con una etiqueta apropiada.

    ######################################

    # Armado de la nueva extension #

    ######################################

    extensionMaybe = Extension(Maybe, expresiones=[Just, Nothing, IsNothing, CaseMaybe], tipos=[TipoMaybe])

    Por ultimo, para que la extension sea detectada por los aplicativos (tanto de consola como la interfaz grafica, es necesarioagregarla a la lista extensionesen registro.py. Esta lista es consultada por las aplicaciones para conocer las extensiones

    que estan disponibles.

  • 7/23/2019 Interprete Calculo Lambda

    28/33

    Castillo, Martnez, Sainz-Trapaga Pagina 25 de30

    Parte 4

    Extensiones

    Los siguientes son los tipos y expresiones definidos p or nosotros a modo de librera.

    4.1. Tipos

    Boolean

    Natural

    Funcion ( )

    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

    Aplicacion (M N)

    Registros:

    construccion de registros

    proyeccion de registros

    Listas:

    Lista vacaagregar elemento adelante (add(E,L))

    case para listas (esquema para pattern matching)

  • 7/23/2019 Interprete Calculo Lambda

    29/33

    Castillo, Martnez, Sainz-Trapaga Pagina 26 de30

    Arboles binarios:

    nil

    constructor de arbol binario (bin(M,N,O))

    case para arboles

    Maybe

    NothingJust

    isNothing

    case para Maybe

    Tuplas

    constructor de tupla

    proyectores

  • 7/23/2019 Interprete Calculo Lambda

    30/33

    Castillo, Martnez, Sainz-Trapaga Pagina 27 de30

    Parte 5

    Posibles extensiones al trabajo

    5.1. Subtipado

    Una ampliacion posible para el traba jo sera la incorporacion de reglas de subtipado. Esto es factible dentro del esquemapropuesto, y la forma simple de hacerlo sera sobrecargar el operador< para los tipos. De este modo, en vez de preguntarsi un tipo es igual a otro, se pregunta por menor o igual al momento de realizar los chequeos de tipos.

    El siguiente codigo implementa la extension de registros:

    class TypeReg(Type):

    """

    El tipo registro estara compuestos por etiquetas con tipos asociados.

    """def init (self, tok ):

    i = 0ids = {}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):ifisinstance(otro, TypeReg):res =Truefor each in self.ids:

    res = res and each in otro.ids and self.ids[each] == otro.ids[each]if(not res):

    return res

    returnlen(self.ids) ==len(otro.ids)else:

    return False

    @classmethoddefsintaxis(cls):

    campo = makeSintaxis(Id, :, TypeExp)listaCampos = Optional(campo + ZeroOrMore(makeSintaxis(",", campo)))

  • 7/23/2019 Interprete Calculo Lambda

    31/33

    Castillo, Martnez, Sainz-Trapaga Pagina 28 de30

    reg = makeSintaxis({, listaCampos,})return reg

    def str (self):s = {primero =True

    for each in self.ids:ifprimero:

    primero =Falses+= 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

  • 7/23/2019 Interprete Calculo Lambda

    32/33

    Castillo, Martnez, Sainz-Trapaga Pagina 29 de30

    5.2. Inferencia de tipos y otras alternativas

    Durante la cursada vimos como implementar el algoritmo de inferencia de tipos para el calculo lambda (que ademasimplemetamos en una clase de laboratior). Por esta razon, decidimos usar tipado simple y no inferencia de tipos paraenfocarnos en el aspecto central de nuestro trabajo que era la simplicidad de extension.

    Del mismo modo, podra construirse como extension futura el agregado de polimorfismo, as como tambien junto coneste considerar el desarrollo de clases de tipos (similares a las de Haskell, donde tenemos Eq para denotar que los tipos tienencomparacion por igual, o Show para denotar a los tipos que tienen una funcion show para ser mostrados por pantalla).

  • 7/23/2019 Interprete Calculo Lambda

    33/33

    Castillo, Martnez, Sainz-Trapaga Pagina 30 de30

    Parte 6

    Conclusion

    Como conclusion final po demos enumerar una serie de conceptos que resultaron de la realizacion de este trabajo practico.

    En primer lugar, y como se explico en la introduccion, la idea de este trabajo era po der lograr un interprete de lambdacalculo que no solo funcionara de manera correcta, sino que tambien pudiese ser extendido para incluir nuevos tipos yexpresiones de forma sencilla.

    Consideramos que este objetivo se cumplio, ya que pudimos elaborar una manera estandar de introducir nuevas extensio-nes al interprete. Ademas, consideramos que hallamos un equilibrio razonable entre la sencillez de extension y la flexibilidadque se permite al agregar nuevos terminos al lengua je. No se utilizaron conveciones extremadamente fuertes que podranhaber causado limitaciones po co practicas para extender el lenguaje de forma extravagante. A su vez, la inclusion del tutorialdebera hacer que la incorporacion de una nueva extension sea un procedimiento sencillo incluso para aquellas personas queno estan familiarizadas con el trabajo ni con el lenguaje Python.

    Por otro lado creemos que el enfoque del trabajo se oriento a uno de los temas mas importantes de la cursada, y que selogro no solo combinarlo con programacion orientada a objetos, sino tambien encontrar una forma dinamica de resolverlo. Si

    bien es cierto que durante la cursada se implementaron cuestiones relacionadas al lambda caculo, la vision de este traba jo esmas compacta y abarca las cuestiones principales del tema (como ser el manejo de tipado, sintaxis, reducci on y extensionesal calculo). Ademas, los trabajos practicos llevados a cabo durante la cursada tuvieron enfoques menos globales que este,que nos permitio construir un interprete de un lengua je de programacion de principio a fin.

    Como senalamos en el apartado anterior, nos hubiese gustado tambien implementar otras cuestiones como es el caso delas reglas de subtipado. Sin embargo, se dejaron las puertas abiertas a dicha extension como se comento anteriormente.

    Consideramos que como punto final a la materia, la realizacion de un trabajo practico constituyo una solucion dinamica einteractiva, y nos permitio utilizar lo aprendido para construir una herramienta completa, que podra tener posibilidades deuso futuro dentro de la materia. Futuros estudiantes pueden examinar el codigo entregado para comprender el funcionamientode un interprete, y servirse de la gran cantidad de extensiones propuestas como referencia para implementar las suyas.