¡Esta es una revisión vieja del documento!
Tabla de Contenidos
Clase 1
Plan para hoy
- Introducción al uso de Hugs
- Como escribir programas Haskell
- Escribiendo los primeros programas
Clase
Hugs es un intérprete del lenguaje funcional puro Haskell.
Durante este taller vamos a utilizarlo para escribir, probar y utilizar los programas funcionales que se dan en el teórico.
A Hugs se lo invoca desde la línea de comandos o picando sobre el ícono en nuestro entorno gráfico. Una vez que el intérprete esta activo, la pantalla se presenta con un prompt a la espera de expresiones a ser evaluadas o commandos.
[nicolasw@azul Taller]$ hugs __ __ __ __ ____ ___ _________________________________________ || || || || || || ||__ Hugs 98: Based on the Haskell 98 standard ||___|| ||__|| ||__|| __|| Copyright (c) 1994-2005 ||---|| ___|| World Wide Web: http://haskell.org/hugs || || Report bugs to: hugs-bugs@haskell.org || || Version: March 2005 _________________________________________ Haskell 98 mode: Restart with command line option -98 to enable extensions Type :? for help Hugs.Base>
En este modo Hugs se convierte en una calculadora esperando que se introduzca una expresión para luego evaluarla y volver a pedir una expresión (lazo leer-evaluar-imprimir). Gracias al preludio standard tenemos muchas funciones ya definidas.
Hugs.Base> 21+21 42 Hugs.Base> 2*4 == 10 `div` 5 && True False Hugs.Base> [2,3,5,7,11]++[1,2] [2,3,5,7,11,1,2] Hugs.Base> reverse "dabale arroz a la zorra el abad" "daba le arroz al a zorra elabad"
Este ciclo continua indefinidamente hasta que pidamos la salida del intérprete con CTRL-D o con el comando
Hugs.Base> :q [Leaving Hugs] [nicolasw@azul Taller]$
Para poder dar nuevas definiciones y/o funciones necesitamos escribir un programa funcional o script Haskell. Un programa funcional es un archivo con terminación .hs donde se escriben en texto plano todas las definiciones que conforman el programa funcional.
A manera de ejemplo realicemos un ciclo de creación-carga-prueba-modificacion-recarga, con el Ejercicio 8.3 del apunte Extracto del Cálculo de Programas.
Para crear un script basta con invocar el comando para editar un (nuevo) archivo :e ejercicios8.hs
.
Una posible solución para el problema de la función signo es la siguiente:
sgn :: Int -> Int sgn x | 0<x = 1 | x<0 = -1 | x=0 = 0
Luego de salvar el programa y cargarlo, el intérprete indica un error pues =
es el símbolo de definición, mientras que el igual lógico es ==
.
Hugs.Base> :e ejercicios8.hs Hugs.Base> :l ej Hugs.Base> :l ejercicios8.hs ERROR "ejercicios8.hs":4 - Syntax error in input (unexpected `=')
Las traducciones son más o menos directas, de todas formas preparamos una tabla de Traducción de Cálculo de Programas a Haskell.
Volvemos a editar el script con :e
(el nombre ya no lo necesitamos ya que tenemos cargado este script) y corregimos el x=0
por x==0
.
Podemos probar la nueva función para ganar confianza en su corrección.
Main> sgn 1 1 Main> sgn 0 0 Main> sgn -1 ERROR - Cannot infer instance *** Instance : Num (Int -> Int) *** Expression : sgn - 1 Main> sgn (-1) -1 Main> sgn 123123123123 Program error: arithmetic overflow Main> sgn 123123123 1 Main> sgn 1.1 ERROR - Cannot infer instance *** Instance : Fractional Int *** Expression : sgn 1.1 Main> sgn (-1 ERROR - Syntax error in expression (unexpected end of input) Main> map sgn [-10..10] [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,1,1,1,1,1,1,1,1,1]
Notamos los distintos tipos de errores que se producen por problemas de
- Precedencia
- Tipos
- Sintáxis
A manera de ejemplo veamos el ejercicio 8.7, donde tenemos que definir una función muy útil para cualquier aparato que maneje un calendario (relojes, celulares, PDAs, computadoras, DVD-R, etc.). La signatura 1) es bisiesto: Int → Bool, y es un predicado que devuelve true si el año es bisiesto y false en caso contrario. Recordemos cuando un año es bisiesto:
La regla completa para los años bisiestos según el calendario Gregoriano es: Un año es bisiesto si es divisible por 4, excepto aquellos divisibles por 100 pero no por 400.
Entonces podemos seguir agregando definiciones de funciones a nuestro archivo ejercicios8.hs
con el comando :e
.
Veamos tres versiones distintas 2).
Ejercicios
Para realizar en lo que resta de la clase.
- Ejercicio 8.7
Definir la función edad : (Nat, Nat, Nat) → (Nat, Nat, Nat) → Int que dadas dos fechas indica los años transcurridos entre ellas. Por ejemplo edad.(20,10,1968).(30,4,1987) = 18
- Ejercicio 8.8
En un prisma rectangular, llamemos h a la altura, b al ancho y d a la profundidad. Completar
la siguiente definición del área del prisma:
area.h.b.d = 2 ∗ frente + 2 ∗ lado + 2 ∗ arriba
|[ …aca va la definicion… ]
donde frente, lado y arriba son las caras frontal, lateral y superior del prisma respectivamente.
bisiesto'' :: Int -> Bool bisiesto'' n = if n `mod` 4 /= 0 then False else if n `mod` 100 /= 0 then True else if n `mod` 400 == 0 then True else FalseEl que está aprendiendo Haskell
bisiesto' :: Int -> Bool bisiesto' n | n `mod` 4 /= 0 = False | n `mod` 4 == 0 = n `mod` 100 /= 0 || n `mod` 400 == 0El que hizo Introducción a los Algoritmos
bisiesto :: Int -> Bool bisiesto n = n `mod` 4 == 0 && (n `mod` 100 /= 0 || n `mod` 400 == 0)Podemos poner las tres versiones en nuestro script y probarlas rápidamente usando la función
filter
para que obtener solo los años bisiestos desde 1945 al 2006.
Main> filter bisiesto [1945..2006] [1948,1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000,2004] Main> filter bisiesto' [1945..2006] [1948,1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000,2004] Main> filter bisiesto'' [1945..2006] [1948,1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000,2004]Podemos comprobar que las tres funciones operan correctamente en el rango de números dados ((eso no quiere decir que sean correcta en su totalidad, solo decimos que en ese rango no tiene fallas