2009-09-25 28 views
21

Estoy leyendo this tutorial en Haskell. Definen composición de funciones como las siguientes: Se proporcionaronHaskell función composición

(.)      :: (b->c) -> (a->b) -> (a->c) 
f . g     = \ x -> f (g x) 

No hay ejemplos, que creo que me ilumine en cuanto a lo que se define aquí.

¿Alguien puede proporcionar un ejemplo simple (con explicación) de cómo se usa la composición de la función?

Respuesta

38

La composición de funciones es una forma de "componer" dos funciones juntas en una sola función. He aquí un ejemplo:

Digamos que tiene estas funciones:

even :: Int -> Bool 
not :: Bool -> Bool 

y desea definir su propia función myOdd :: Int -> Bool usando los dos anteriores.

La manera obvia de hacerlo es la siguiente:

myOdd :: Int -> Bool 
myOdd x = not (even x) 

Pero esto se puede hacer de forma más sucinta usando la composición de funciones:

myOdd :: Int -> Bool 
myOdd = not . even 

Los myOdd funciones se comportan exactamente igual, pero el segundo uno se crea "pegando" dos funciones juntas.

Un escenario donde esto es especialmente útil es eliminar la necesidad de una lambda explícita. Por ejemplo:

map (\x -> not (even x)) [1..9] 

puede reescribirse a:

map (not . even) [1..9] 

un poco más corto, menos espacio para errores.

+0

¿Cómo es que no necesita mostrar el parámetro de entrada en la definición? Por ejemplo. ¿Cómo es que no escribes 'myOdd x = not. incluso x'? – unclerojelio

+2

@unclerojelio Se llama estilo sin puntos. En lugar de definir 'myOdd' en términos del resultado para un argumento dado (" Dado 'x',' myOdd' devuelve el mismo valor que '(not. Even) x'"), se define en términos de lo que realmente es is ("' myOdd' es la función que resulta cuando 'not' se compone con' even' "). – chepner

13

El composición de f y g es una función que primero se aplica g a su argumento, a continuación, 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 usted tiene un fondo de Java/C, considere este ejemplo:

int f(int x); 
int g(int x); 
int theComposition(int x) { return f(g(x)); } 
+0

+1 para la equivalencia – outis

4

Desde el HaskellWiki page on function composition:

desort = (reverse . sort) 

ahora desort es una función que ordena una lista al revés. Básicamente, desort introduce sus argumentos en sort, y luego envía el valor de retorno desde sort al reverse, y lo devuelve. Entonces lo ordena, y luego invierte la lista ordenada.

7

Este ejemplo es artificial, pero supongamos que tenemos

sqr x = x * x 
inc x = x + 1 

y queremos escribir una función que calcula x^2 + 1. Podemos escribir

xSquaredPlusOne = inc . sqr 

(que significa

xSquaredPlusOne x = (inc . sqr) x 

que significa

xSquaredPlusOne x = inc(sqr x) 

desde f = inc y g = SQR).

26

Nota al pie de la diversión. La composición de la función es el equivalente de un silogismo en la 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 sola:

(Man => Mortal), (Socrates => Man), therefore (Socrates => Mortal) 

Por lo tanto ...

(b -> c) -> (a -> b) -> (a -> c) 

... que es el tipo de la función de ..

3

La composición de funciones es una forma de encadenar dos o más funciones juntas. A menudo se compara con tuberías de concha. Por ejemplo, en una cáscara de estilo Unix, es posible escribir algo como

cat foo.txt | sort -n | less 

Esto va en cat, alimenta su salida a sort, y alimenta la salida de aquél al less.

Estrictamente, esto es como el operador Haskell $. Puede 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 ejecutamos filter sobre él, luego lo sort, y luego calculamos el sum de él.

El operador de composición de funciones, ., hace algo similar. El ejemplo anterior produce un número ; el ejemplo de arriba genera una función :

sum . sort . filter (> 0) 

en cuenta que en realidad no alimentar a una lista en esto. En cambio, acabamos de crear una nueva función, y podemos alimentar varias listas diferentes para esa función.Por ejemplo, es posible que el nombre de esta función:

my_function = sum . sort . filter (> 0) 

O puede pasar como argumento a otra función:

map (sum . sort . filter (> 0)) my_lists 

básicamente se puede usar en cualquier lugar que se puede utilizar cualquier otro tipo de función . Es solo una forma rápida y legible de decir "Quiero encadenar estas funciones juntas".

Cuestiones relacionadas