function haskell functional-programming composition

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.