# LAB 01 - Paradigmas 2022 ###### Integrantes: Franco Artico, Francisco Percivaldi y Martin Piloni El laboratorio consistió en la **implementación** de lo que se llama un _DSL_ basado en el [siguiente paper](https://cs.famaf.unc.edu.ar/~mpagano/henderson-funcgeo2.pdf), en _Haskell_. ## ¿Qué es un DSL? Un lenguaje de domino específico (o _**D**omain-**S**pecific **L**anguage_) es un lenguaje de programación, el cual posee un cierto nivel de abstracción y está dirigido para resolver un tipo particular de problemas. ### El problema a tratar En nuestro caso, debiamos construir un _DSL_ en _Haskell_ con el que sea posible especificar la composición de dibujos geométricos. Para luego, construir a partir de figuras básicas un diseño e imprimir dicho diseño a través del uso de una bibliotéca de gráficos, la cual en nuestro caso es **Gloss**. ![](https://i.imgur.com/cRNkB57.png) Sin embargo, para tener un lenguaje necesitabamos definir la **sintaxis** y la **semántica** del mismo. ## Separación de módulos La **semántica** y la **sintaxis** se definieron en módulos diferentes, a continuación daremos una lista con los módulos y cual es la funcionalidad dentro del programa desarrollado, junto con nuestra experiencia desarrollándolos. ## ```Dibujo.hs``` #### Definición del tipo ```Dibujo``` Fue el primer módulo que completamos, empezando por la definición de nuestro lenguaje apoyandonos en la estructura dada por la cátedra en [la consigna](https://docs.google.com/document/d/1qtVP_6MtvyEdM4sLGqnn7MeQ0KmJ7xcMqhRz20qelDI/edit#heading=h.1uqnq378gi02) del laboratorio. ![](https://i.imgur.com/Buzi6VP.png) Aquí fue donde encontramos nuestra **primera dificultad**, nos llevo tiempo darnos cuenta que debíamos colocar en lugar de ```<fig>```, hasta que finalmente nos dimos cuenta que era como se referían al tipo ```Dibujo``` en la consigna. #### Definición de combinadores Lo siguiente, era desarrollar un par de funciones llamadas **combinadores** que nos permitían combinar programas definidos con el nuevo tipo de dato```Dibujo```. Aquí se nos presentó otra complicación cuando tuvimos que usar el constructor ```Apilar``` en la siguiente función: ```haskell (.-.) :: Dibujo a -> Dibujo a -> Dibujo a (.-.) x y = Apilar 1 1 x y ``` Debido a que no sabíamos que números teníamos que pasarle como parámetro, hasta que un profe nos resolvió la duda y entendimos que esos números marcaban una proporción y no importaba (en este caso) que valor le pasaramos, pero si que dicho valor sea igual en ambos. El resto de los combinadores nos salió sin mayores complicaciones. #### Definición de esquemas Estos esquemas nos ayudarán a manipular figuras básicas. Aquí, en las primeras dos funciones que consisten en tomar un elemento polimorfíco y verlo como una figura y en un map para nuestro lenguaje, no hubo complicaciones, sin embargo al llegar a ```sem``` nos costó bastente entender como es que este debía de implementarse, y luego de implementarlo entendimos que este **tenia un gran potencial** para completar el resto del módulo. #### Definición de funciones sobre predicados Los predicados nos sirven para poder **verificar propiedades** dentro de nuestro lenguaje. Es por eso que entre estas funciones podemos encontrar ```any``` y ```all``` que nos permite saber si *alguna* expresión o *todas* las expresiones cumplen una cierta propiedad dada, ó ```and``` y ```or``` que nos sirven para verificar una combinación de propiedades, es decir, si una o varias expresiones cumplen con "una o otra" propiedad o ambas propiedades. También podemos encontrar dentro de estas funciones a ```desc``` que dado un ```Dibujo``` nos da una pequeña descripción sobre él y ```básicas``` que arma una lista con todas las figuras básicas de un dibujo. #### Definición de predicados Los predicados de esta sección de código nos permiten **encontrar operaciones que no producen ningún cambio en el dibujo**, sino que de lo contrario, estas operaciones dejan el Dibujo tal cual lo tomaron. Es decir, que es lo mismo que estén a que no estén. En particular ```esrot360``` verifica si hay una rotación de 360 grados y ```esFlip2``` verifica si un dibujo se espejó dos veces. #### Definición de una función de chequeo de errores ```check``` es una función que realiza un filtrado de una figura para indicar si la misma, contiene o no superfluidad en las operaciones que la constituyen. En esta función **tomamos una decisión dado a que consideremos que hay una ambiguedad en el enunciado** de devolver **el tipo de error** ```RotacionSuperflua``` o ``FlipSuperfluo``` si este se encuentra dentro de la figura y no la **cantidad** de errores de cada tipo que la figura contenga. A continuación dejamos un ejemplo para facilitar la comprensión del lector, **decidimos imprimir** ``` bash *main> check (Espejar(Espejar(Espejar(Espejar(Basica 6))))) *main> Left [FlipSuperfluo] ``` en vez de ``` bash *main> check (Espejar(Espejar(Espejar(Espejar(Basica 6))))) *main> Left [FlipSuperfluo, FlipSuperfluo] ``` En resumen, ```dibujo.hs``` define la **sintaxis de nuesto lenguaje**. Define las **combinaciones admitidas** dentro del mismo, también aquellas que no son admitidas (como es el caso de la combinación de operaciones _superfluas_), **el orden** que van a tener nuestras expresiones (mediante la definición de nuestro lenguaje en ```Dibujo```) y los **predicados** que son indispensables para hacer que una expresión tenga sentido. Es decir, dá un **conjunto de reglas** que se deben cumplir para que las expresiones puedan tener significados que **sean reconocibles**. ### ```Interp.hs``` En este módulo están las funciones que corresponden con la **semántica de las operaciones nuestro lenguaje**, la cual se representará mediante la interpretación geométrica de las figuras generadas por el lenguaje, con la **librería gloss**. La semántica de cada operación de nuestro lenguaje está dada por las siguiente tabla. ![](https://i.imgur.com/hJUQl7R.png) A efecto de implementar estas funciones matematicas, tuvimos que hacer uso de los vectores otorgados por _Gloss_. Una vez implementadas, necesitabamos de una funcion que interprete expresiones de operaciones combinadas de nuestro lenguaje. Para eso, completamos ```interp```, la cual funciona de la siguiente manera: - Toma una figura básica, una expresión en nuestro lenguaje y toma tres vectores para inicializar las coordenadas del dibujo. - Aplica las operaciones dentro de la expresión a figura básica con el uso de funciones definidas anteriormente. - Devuelve un ```Picture``` que es lo que finalmente interpretará _Gloss_. ## ```Main.hs``` A partir de una configuración, imprime en pantalla el dibujo tomando en cuenta la interpretación de las figuras básicas. ## ```Escher.hs``` En este módulo, se define el tipo de datos donde se encuentran las figuras que podemos usar para el dibujo de _Escher_ ```haskell data Escher = Blank | Triangle1Escher | Triangle2Escher | TriangleDEscher| RectangleEscher | FEscher ``` Junto con la definición de los siguientes combinadores, basados en el paper de _Henderson_. : * *lado*. * *esquina*. * *noneto*. Para los dos primeros, hacemos uso de la figuras ```DibujoU``` y ```DibujoT```. ![](https://i.imgur.com/INCHeqQ.png) También definimos la fórmula para hacer el dibujo de _Escher_, en la función ```escher```. Luego, usamos ```draw```para devolver nuestro dibujo de Escher con el _nivel de recursión_ que se especifíque dentro de la función. Finalmente, en ```interpBas``` a cada constructor se le asigna una figura (triángulo, rectángulo, F) representada con 3 vectores para hacer el dibujo de _Escher_ en base a estas. ### Modificación a la partición de Módulos Nos pareció correcto dividir el módulo ```Dibujo.hs```, colocando los predicados en un módulo aperte llamado ```Pred.hs``` debido a que no estaba implementando combinadores del lenguaje, sino haciendo verificaciones sobre las propiedades del mismo. ## ¿Por qué las figuras básicas no están incluidas en la definición del lenguaje, y en vez es un parámetro del tipo? Debido a que de esta forma lo que obtenemos es una definción del lenguaje polimorfíca, gracias a esto podemos usar cualquier figura como base para crear un dibujo, sin cambiar la definición del lenguaje. Además, podemos añadir nuevas figuras para el dibujo en el momento que lo necesitemos. ## Explique cómo hace Interp.grid para construir la grilla, explicando cada pedazo de código que interviene. ¡Ojo! Si mal no recuerdo hay un error sutil… Para entender ```grid``` primero debemos entender ```hlines```, esta función crea líneas horizontales que empieza en un punto ```(x,y+h)``` y trazan una línea hasta el punto ```(x+mag, y+h)```.```mag``` es un parámetro que define la longitud de la línea y ```h```, que está definido a través del parámetro ```sep```, indica la separación vertical entre cada línea. Ahora sí, ```grid``` crea ```n + 1``` líneas horizontales y las junta en una ```Picture```. Luego, crea nuevas líneas horizontales y las rota en 90º, dejando así, líneas vérticales y las sube ```sep * n``` en el eje ```y```, para que se intersequen con las líneas horizontales. Esto se une en una nueva ```Picture```, junto a las líneas horizontales, formando así una grilla. Cabe destacar que la función original ```grid``` dada por la cátedra **tenía un "error"** y era que los nombres de los parámetros ```mag```, ```l``` estaban intercambiados de lugar, pues en ```hlines``` se usa el parámetro ```sep```como la **separación de las líneas** y en esta función se usa como la **longitud de la líneas** al llamar a ```hlines``` en la función ```ls``` dentro de ```Grid```. #### El código con el "error" ```haskell grid :: Int -> Vector -> Float -> Float -> Picture grid n v sep l = pictures [ls,translate 0 (l*toEnum n) (rotate 90 ls)] where ls = pictures $ take (n+1) $ hlines v sep l ``` #### El código corregido ```haskell grid :: Int -> Vector -> Float -> Float -> Picture grid n v l sep = pictures [ls,translate 0 (sep*toEnum n) (rotate 90 ls)] where ls = pictures $ take (n+1) $ hlines v l sep ```