Haskell Hero
Haskell Hero es un manual interactivo del lenguaje Haskell para principiantes.
|
|
Tipo de funciones compuestasUn ejemplo simple 1
¿Qué es el tipo de la función
En la lección Funciones útiles podéis encontrar esta función representada por una caja. Para repetir: ¿Qué es el tipo de función? Es una definición de tipos de valores que entran en la función y el tipo del valor al que se evalúa la función. Todas las partes están separadas por flechas El tipo de una función compuesta consta entonces de valores que entran al principio y de las que se devuelven al fin. Valores de resultados intermedio no nos interesan.
Como podemos ver en el imagen de la otra lección, la función odd . snd :: (a, Integer) -> Bool Un ejemplo simple 2
¿Qué es el tipo de la función
La función head [3,4,5] ~> 3
Sin embargo, si aplicamos la función (head . head) [3,4,5] ~> head (head [3,4,5]) ~> head 3 ~/>
Quisieramos que la primera aplicación de la función (head . head) [[3,10,14], [8,4,13,15], []] ~> head (head [[3,10,14], [8,4,13,15], []]) ~> head [3,10,14] ~> 3
Ya que el tipo de lista de entrada no es importante para la función head . head :: [[a]] -> a Convertimos en pointwise
Pointwise es una notación opuesta a la notación en estilo pointfree. En la expresión pointfree la lambda se sustituye por operadores Para la conversión de pointfree a pointwise necesitamos solo tres reglas:
Un ejemplo más complejo
Definid el tipo más general de la función Esta tarea se puede resolver de muchas maneras. Aquí mostramos la conversión de la función al estilo pointwise y después la declaración de tipo de ella.
Primero hay que decidir donde poner las paréntesis.
((.(,)) . (.)) . (,) o (.(,)) . ((.) . (,)) En la tabla de prioridades y asociación encontramos que (.) asocia de la derecha, lo que significa que las paréntesis se deberían poner de manera siguiente:
(.(,)) . ((.) . (,)) Ahora ya podemos empezar con la propia conversión al estilo pointwise. Durante la conversión al estilo pointfree estabamos quitando los parámetros. Aquí vamos a añadirlos. Aplicamos entonces la nuestra función al parámetro x.
\x -> ((.(,)) . ((.) . (,))) x La expresión la modificamos según la definición de (.): (nota: el signo ===> es solo un signo definido por nosotros para la reducción de la notación, no es un operador de Haskell. Significa "vamos a convertir esto en esto")
\x -> ((.(,)) . ((.) . (,))) x
(--f--- . -----g-----) x
===>
\x -> (.(,)) (((.) . (,)) x)
-- f - (---- g ---- x)
Ahora utilizamos el hecho de que (+5) 3 es lo mismo que 3 + 5.
\x -> (.(,)) (((.) . (,)) x)
(+ 5 ) (----- 3 -----)
===>
\x -> (((.) . (,)) x) . (,)
(----- 3 -----) + 5
Ahora modificamos ((.) . (,)) x según la definición de (.).
\x -> (((.) . (,)) x) . (,)
( f . g ) x
===>
\x -> ((.) ((,) x)) . (,)
f ( g x)
Ahora ya hemos convertido todo lo que podíamos pero la función todavía no está en el estilo pointwise. Añadimos entonces un nuevo parámetro general, por ejemplo y.
\x y -> (((.) ((,) x)) . (,)) y Ahora podemos utilizar la definición de (.) otra vez.
\x y -> (((.) ((,) x)) . (,)) y
(----- f ----- . g ) y
===>
\x y -> ((.) ((,) x)) ((,) y)
----- f ----- ( g x)
En este momento tenemos la expresión en la forma ((+) 3) 5 y lo vamos a convertir en 3 + 5.
\x y -> ((.) ((,) x)) ((,) y)
((+) -- 3 --) -- 5 --
===>
\x y -> ((,) x) . ((,) y)
-- 3 -- + -- 5 --
Ahora no podemos modificar la notación de ninguna manera pero todavía no es una expresión que se evalúe completamente. Por eso aplicamos toda la expresión a un argumento nuevo que llamamos por ejemplo z.
\x y z -> (((,) x) . ((,) y)) z Después quitamos el operador (.) de manera típica.
\x y z -> (((,) x) . ((,) y)) z
(-- f -- . -- g --) x
===>
\x y z -> ((,) x) (((,) y) z)
-- f -- (-- g -- x)
Todos los operadores (.) están quitados, ahora nos queda solo convertir la definición en la notación infija para que sea más claro. Primero convertimos la subexpresión ((,) y) z.
\x y z -> ((,) x) (((,) y) z)
((+) 3) 5
===>
\x y z -> ((,) x) (y,z)
3+5
Y luego toda la expresión.
\x y z -> ((,) x) (y,z)
((+) 3) - 5 -
===>
\x y z -> (x,(y,z))
3+ -5-
¿A qué hemos llegado?
No podíamos decir nada sobre la función
¿Qué es entonces el tipo de la función (.(,)) . (.) . (,) :: a -> b -> c -> (a,(b,c)) |