[F#] Composición de funciones y conversión eta

Las funciones en F# tiene asociatividad de izquierda a derecha, esto es, dada la función:

let f g h i = g h i

Será lo mismo que (g h) i. Aplicando parcialmente g h y pasando i como argumento a la función resultante.

Teniendo presente el concepto de asociatividad de funciones, entonces ¿qué es la composición de funciones? en matemáticas Wikipedia dice:

Dadas dos funciones, bajo ciertas condiciones podemos usar los valores de salida de una de ellas como valores de entrada para la otra., creando una nueva función.

Lo que sería, aplicar una función al resultado de otra -> f(x) -> g(x) ->. Lo podemos representar de la forma (g ∘ f)(x) = g(f(x)).

Haciendo el ejercicio en álgebra, podríamos ver algo como lo siguiente.

Dadas las funciones:
f(x) = 2x²+3x
g(x) = 5x-2

(f ∘ g)(x) = f(g(x))
(f ∘ g)(x) = f(5x-2) = 2(5x-2)² + 3(5x-2)

Para verlo más claro en el código veamos un ejemplo. Dadas las funciones:

not //(bool -> bool) 
esPar //(int -> bool)

Crear una función esImpar (int -> bool)

Un primer enfoque podría ser:

let esImpar x = not(esPar(x))

Nótese que haciendo uso de los paréntesis estamos cambiando la asociatividad y hacemos explicito que se avalúe primero la función esPar.

Con esto se ve ya un poco más claro, y menos difícil de entender el f(g(x)). Con lo que podríamos entonces escribir una función que nos ayude con dicha composición, algo como:

let compoc f g x = f(g(x))

compoc tendrá la firma f:('a -> 'b) -> g:('c -> 'a) -> x:'c -> 'b

Podríamos usarla así:

let esImpar x = compoc not esPar x

Y podríamos simplificarlo un poco más haciendo uso de la conversión eta (η-conversión), que, en resumen y como entiendo su aplicación: si el último argumento está en los dos lados de la expresión podemos removerlo. En nuestro caso, en la expresión esImpar x = compoc not esPar x. El último y único argumento es x, y aparece en los dos lados de la expresión, por lo que sería lo mismo escribir:

let esImpar = compoc not esPar

Teniendo claro que F# es un lenguaje “functional first” era de esperarse que exista ya un operador para la composición de funciones, así como en Haskell tenemos el “.“, en F# tenemos el >> (forward composition operator).

La definición de este operador es:

let (>>) f g x = g(f x)

Qué es muy similar a lo que teníamos, dadas dos funciones f y g calculamos f(x) y pasamos su resultado a g.

Haciendo uso de este operador podemos reescribir nuestra función así:

let esImpar = esPar >> not

¿Qué pasa si las funciones tienen más parámetros? Podemos usar este operador sin problema y dado que su prioridad es más baja que las otras funciones no debemos preocuparnos por agruparlas con paréntesis, a diferencia de nuestra primera implementación. De esta forma conseguimos código más conciso.

Espero les sea de utilidad.
hasta el próximo post.

Anuncios
[F#] Composición de funciones y conversión eta

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s