function - Composición de la función haskell
functional-programming composition (6)
Desde la página de HaskellWiki en la composición de la función:
desort = (reverse . sort)
Ahora desort
es una función que ordena una lista a la inversa. Básicamente, desort
alimenta sus argumentos en sort
, y luego alimenta el valor de retorno de sort
en reverse
, y eso lo devuelve. Así que lo ordena, y luego invierte la lista ordenada.
Estoy leyendo this tutorial en Haskell. Definen la composición de la función como la siguiente:
(.) :: (b->c) -> (a->b) -> (a->c)
f . g = / x -> f (g x)
No se proporcionaron ejemplos, lo que creo me iluminaría sobre lo que se define aquí.
¿Puede alguien proporcionar un ejemplo simple (con explicación) de cómo se utiliza la composición de funciones?
Este ejemplo es artificial, pero supongamos que tenemos
sqr x = x * x
inc x = x + 1
y queremos escribir una función que calcule x ^ 2 + 1. Podemos escribir
xSquaredPlusOne = inc . sqr
(lo que significa
xSquaredPlusOne x = (inc . sqr) x
lo que significa
xSquaredPlusOne x = inc(sqr x)
ya que f = inc yg = sqr).
La composición de f
y g
es una función que primero aplica g
a su argumento, luego f
al valor devuelto por g
. A continuación, devuelve el valor de retorno de f
.
Esta identidad puede ser esclarecedor:
f (g x) = (f . g) x
Si tiene un fondo Java / C, considere este ejemplo:
int f(int x);
int g(int x);
int theComposition(int x) { return f(g(x)); }
La composición de funciones es una forma de "componer" dos funciones juntas en una sola función. Aquí hay un ejemplo:
Digamos que tienes estas funciones:
even :: Int -> Bool
not :: Bool -> Bool
y desea definir su propia función myOdd :: Int -> Bool
usando las dos anteriores.
La forma obvia de hacer esto es la siguiente:
myOdd :: Int -> Bool
myOdd x = not (even x)
Pero esto se puede hacer más sucintamente usando la composición de la función:
myOdd :: Int -> Bool
myOdd = not . even
Las funciones myOdd
comportan exactamente igual, pero la segunda se crea al "pegar" dos funciones juntas.
Un escenario donde esto es especialmente útil es eliminar la necesidad de un lambda explícito. P.ej:
map (/x -> not (even x)) [1..9]
se puede reescribir a
map (not . even) [1..9]
Un poco más corto, menos espacio para errores.
La composición de funciones es una forma de encadenar dos o más funciones. A menudo se compara con la tubería de shell. Por ejemplo, en un shell de estilo Unix, puede escribir algo como
cat foo.txt | sort -n | less
Esto ejecuta cat
, alimenta su salida para sort
, y alimenta la salida de eso a less
.
Estrictamente, esto es como el operador Haskell $
. Usted podría escribir algo como
sum $ sort $ filter (> 0) $ my_list
Observe que, a diferencia del ejemplo de shell, esto se lee de derecha a izquierda. Así que comenzamos con my_list
como entrada, luego pasamos el filter
encima, luego lo my_list
y luego calculamos la sum
.
El operador de composición de funciones,. , hace algo similar. El ejemplo anterior produce un número ; el siguiente ejemplo produce una función :
sum . sort . filter (> 0)
Tenga en cuenta que en realidad no hemos introducido una lista en esto. En su lugar, acabamos de crear una nueva función y podemos alimentar varias listas diferentes para esa función. Por ejemplo, podrías nombrar esta función:
my_function = sum . sort . filter (> 0)
O podría pasarlo como un argumento a otra función:
map (sum . sort . filter (> 0)) my_lists
Básicamente, puede usarlo en cualquier lugar que pueda usar cualquier otro tipo de función. Es solo una forma rápida y legible de decir "Quiero encadenar estas funciones".
Nota al margen de diversión. La composición de funciones es el equivalente de un silogismo en lógica:
Todos los hombres son mortales. Sócrates es un hombre. Por lo tanto, Sócrates es mortal.
Un silogismo compone dos implicaciones materiales en una:
(Man => Mortal), (Socrates => Man), therefore (Socrates => Mortal)
Por lo tanto...
(b -> c) -> (a -> b) -> (a -> c)
... cual es el tipo de .
función.