En la segunda parte de la clase de hoy de Informática de 1º del Grado en Matemáticas se ha ecplicado el uso de las libretías HLint y Trace.
La librería HLint se instala ejecutando en una consola
Para explicar el uso de HLint se considera el programa ej1.hs
en el que está definida la suma de una lista de números y cuyo contenido es
|
suma :: [Int] -> Int suma [] = 0 suma (x:xs) = x + suma xs |
para analizarlo, se ejecuta en una consola
|
tmp> hlint ej.hs ej.hs:2:1: Warning: Use foldr Found: suma [] = 0 suma (x : xs) = x + suma xs Why not: suma xs = foldr (+) 0 xs 1 suggestion |
Siguiendo la sugerencia, cambiamos el contenido del programa ej1.hs
y queda
|
suma :: [Int] -> Int suma xs = foldr (+) 0 xs |
Lo volvemos a analizar con HLint
|
tmp> hlint ej1.hs ej1.hs:2:1: Error: Eta reduce Found: suma xs = foldr (+) 0 xs Why not: suma = foldr (+) 0 ej1.hs:2:11: Error: Use sum Found: foldr (+) 0 Why not: sum 2 suggestions |
Con lo que finalmente el programa queda
|
suma :: [Int] -> Int suma = sum |
y al analizarlo
|
tmp> hlint ej1.hs No suggestions |
El segundo ejemplo que se explicó es en un programa con acumulador. El programa está en el fichero ej2.hs
cuyo contenido es
|
suma :: [Int] -> Int suma xs = aux 0 xs where aux y [] = y aux y (x:xs) = aux (y+x) xs |
Lo analizamos con HLint
|
tmp> hlint ej2.hs ej2.hs:2:1: Error: Eta reduce Found: suma xs = aux 0 xs Why not: suma = aux 0 ej2.hs:3:9: Warning: Use foldl Found: aux y [] = y aux y (x : xs) = aux (y + x) xs Why not: aux y xs = foldl (+) y xs 2 suggestions |
Al incorporar las 2 sugerencias a ej2.hs
el programa queda como sigue
|
suma :: [Int] -> Int suma = aux 0 where aux y xs = foldl (+) y xs |
Lo volvemos a analizar con HLint
|
tmp> hlint ej2.hs ej2.hs:3:9: Error: Eta reduce Found: aux y xs = foldl (+) y xs Why not: aux = foldl (+) 1 suggestion |
a incorporar la sugerencia a ej2.hs
cuyo contenido queda como sigue
|
suma :: [Int] -> Int suma = aux 0 where aux = foldl (+) |
Lo vovemos a analizar con HLint
|
tmp> hlint ej2.hs No suggestions |
Aunque no ha dado ninguna sugerencia, podemos eliminar la dunción auxiliar aux
quedando el contenido de ej2.hs
como sigue
|
suma :: [Int] -> Int suma = foldl (+) 0 |
Lo analizamos con HLint
|
tmp> hlint ej2.hs ej2.hs:2:8: Error: Use sum Found: foldl (+) 0 Why not: sum 1 suggestion |
Con lo que el program final se reduce a
|
suma :: [Int] -> Int suma = sum |
Para explicar la librería Trace volvemos a considerar la 2ª definición de la suma de los elemntos de una lista; es decir, la versión inicial del ej2.hs
|
suma :: [Int] -> Int suma xs = aux 0 xs where aux y [] = y aux y (x:xs) = aux (y+x) xs |
Para usar la librería Trace
hauy que importarla añadiendo al principio del fichero la línea
Como la función recursiva es aux
, para seguir su traza le añadimos como primera ecuación la siguiente.
|
aux y xs | trace ("aux " ++ show y ++ " " ++ show xs) False = undefined |
Con estos cambios, el contenido del fichero es
|
import Debug.Trace suma :: [Int] -> Int suma xs = aux 0 xs where aux y xs | trace ("aux " ++ show y ++ " " ++ show xs) False = undefined aux y [] = y aux y (x:xs) = aux (y+x) xs |
Al evaluarlo
|
λ> suma [3,2,4] aux 0 [3,2,4] aux 3 [2,4] aux 5 [4] aux 9 [] 9 |
se observa la traza. La cadena de la traza se puede construir con la función printf
de la librería Printf como se muestra a continuación
|
import Debug.Trace import Text.Printf (printf) suma :: [Int] -> Int suma xs = aux 0 xs where aux y xs | trace (printf "aux %2d %s" y (show xs)) False = undefined aux y [] = y aux y (x:xs) = aux (y+x) xs |
en donde se ha ajustado el ancho de la la columna del acumulador a 2 (mediante %2d
) como se ve en la evaluación
|
λ> suma [3,2,7] aux 0 [3,2,7] aux 3 [2,7] aux 5 [7] aux 12 [] 12 |