Haskell Language
Funciones de orden superior
Buscar..
Observaciones
Las funciones de orden superior son funciones que toman funciones como parámetros y / o devuelven funciones como valores de retorno.
Conceptos básicos de las funciones de orden superior
Revise la Solicitud Parcial antes de proceder.
En Haskell, una función que puede tomar otras funciones como argumentos o devolver funciones se denomina función de orden superior .
Las siguientes son todas las funciones de orden superior :
map :: (a -> b) -> [a] -> [b]
filter :: (a -> Bool) -> [a] -> [a]
takeWhile :: (a -> Bool) -> [a] -> [a]
dropWhile :: (a -> Bool) -> [a] -> [a]
iterate :: (a -> a) -> a -> [a]
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
scanr :: (a -> b -> b) -> b -> [a] -> [b]
scanl :: (b -> a -> b) -> b -> [a] -> [b]
Estos son particularmente útiles porque nos permiten crear nuevas funciones además de las que ya tenemos, pasando las funciones como argumentos a otras funciones. De ahí el nombre, funciones de orden superior .
Considerar:
Prelude> :t (map (+3))
(map (+3)) :: Num b => [b] -> [b]
Prelude> :t (map (=='c'))
(map (=='c')) :: [Char] -> [Bool]
Prelude> :t (map zipWith)
(map zipWith) :: [a -> b -> c] -> [[a] -> [b] -> [c]]
Esta capacidad para crear funciones fácilmente (como, por ejemplo, mediante una aplicación parcial como se usa aquí) es una de las características que hace que la programación funcional sea particularmente poderosa y nos permite obtener soluciones cortas y elegantes que de otra forma tomarían docenas de líneas en otros idiomas. Por ejemplo, la siguiente función nos da el número de elementos alineados en dos listas.
aligned :: [a] -> [a] -> Int
aligned xs ys = length (filter id (zipWith (==) xs ys))
Expresiones lambda
Las expresiones Lambda son similares a las funciones anónimas en otros idiomas.
Las expresiones Lambda son fórmulas abiertas que también especifican variables que deben vincularse. La evaluación (encontrar el valor de una llamada de función) se logra sustituyendo las variables enlazadas en el cuerpo de la expresión lambda, con los argumentos proporcionados por el usuario. En pocas palabras, las expresiones lambda nos permiten expresar funciones mediante la vinculación y sustitución de variables.
Las expresiones Lambda se ven como
\x -> let {y = ...x...} in y
Dentro de una expresión lambda, las variables en el lado izquierdo de la flecha se consideran unidas en el lado derecho, es decir, el cuerpo de la función.
Considera la función matemática.
f(x) = x^2
Como una definición de Haskell es
f x = x^2
f = \x -> x^2
lo que significa que la función f
es equivalente a la expresión lambda \x -> x^2
.
Considere el parámetro del map
funciones de orden superior, que es una función de tipo a -> b
. En caso de que se use solo una vez en una llamada al map
y en ninguna otra parte del programa, es conveniente especificarla como una expresión lambda en lugar de nombrar dicha función desechable. Escrito como una expresión lambda,
\x -> let {y = ...x...} in y
x
tiene un valor de tipo a
, ...x...
es una expresión de Haskell que se refiere a la variable x
, y y
tiene un valor de tipo b
. Así, por ejemplo, podríamos escribir lo siguiente
map (\x -> x + 3)
map (\(x,y) -> x * y)
map (\xs -> 'c':xs) ["apples", "oranges", "mangos"]
map (\f -> zipWith f [1..5] [1..5]) [(+), (*), (-)]
Zurra
En Haskell, todas las funciones se consideran como curry: es decir, todas las funciones en Haskell toman solo un argumento.
Tomemos la función div
:
div :: Int -> Int -> Int
Si llamamos a esta función con 6 y 2, no es sorprendente que obtengamos 3:
Prelude> div 6 2 3
Sin embargo, esto no se comporta del modo que podríamos pensar. El primer div 6
se evalúa y devuelve una función de tipo Int -> Int
. Esta función resultante se aplica entonces al valor 2 que produce 3.
Cuando observamos la firma de tipo de una función, podemos cambiar nuestro pensamiento de "toma dos argumentos del tipo Int
" a "toma un Int
y devuelve una función que toma un Int
". Esto se reafirma si consideramos que las flechas en la notación de tipo están asociadas a la derecha , por lo que div
puede leerse así:
div :: Int -> (Int -> Int)
En general, la mayoría de los programadores pueden ignorar este comportamiento al menos mientras aprenden el idioma. Desde un punto de vista teórico , "las pruebas formales son más fáciles cuando todas las funciones se tratan de manera uniforme (un argumento hacia adentro, un resultado hacia afuera)".