Haskell - Funciones

Las funciones juegan un papel importante en Haskell, ya que es un lenguaje de programación funcional. Al igual que otros idiomas, Haskell tiene su propia definición y declaración funcional.

  • La declaración de función consta del nombre de la función y su lista de argumentos junto con su salida.

  • La definición de función es donde realmente define una función.

Tomemos un pequeño ejemplo de add función para comprender este concepto en detalle.

add :: Integer -> Integer -> Integer   --function declaration 
add x y =  x + y                       --function definition 

main = do 
   putStrLn "The addition of the two numbers is:"  
   print(add 2 5)    --calling a function

Aquí, hemos declarado nuestra función en la primera línea y en la segunda línea, hemos escrito nuestra función real que tomará dos argumentos y producirá una salida de tipo entero.

Como la mayoría de los otros lenguajes, Haskell comienza a compilar el código desde el mainmétodo. Nuestro código generará la siguiente salida:

The addition of the two numbers is:
7

La coincidencia de patrones

La coincidencia de patrones es un proceso de coincidencia de tipos específicos de expresiones. No es más que una técnica para simplificar su código. Esta técnica se puede implementar en cualquier tipo de clase Type. If-Else se puede utilizar como una opción alternativa de coincidencia de patrones.

Pattern Matching se puede considerar como una variante del polimorfismo dinámico en el que, en tiempo de ejecución, se pueden ejecutar diferentes métodos según su lista de argumentos.

Eche un vistazo al siguiente bloque de código. Aquí hemos utilizado la técnica de Pattern Matching para calcular el factorial de un número.

fact :: Int -> Int 
fact 0 = 1 
fact n = n * fact ( n - 1 ) 

main = do 
   putStrLn "The factorial of 5 is:" 
   print (fact 5)

Todos sabemos calcular el factorial de un número. El compilador comenzará a buscar una función llamada "hecho" con un argumento. Si el argumento no es igual a 0, entonces el número seguirá llamando a la misma función con 1 menos que el del argumento real.

Cuando el patrón del argumento coincide exactamente con 0, llamará a nuestro patrón, que es "hecho 0 = 1". Nuestro código producirá el siguiente resultado:

The factorial of 5 is:
120

Guardias

Guardses un concepto muy similar a la coincidencia de patrones. En la coincidencia de patrones, generalmente hacemos coincidir una o más expresiones, pero usamosguards para probar alguna propiedad de una expresión.

Aunque es aconsejable utilizar la coincidencia de patrones guards, pero desde la perspectiva de un desarrollador, guardses más legible y simple. Para usuarios nuevos,guards pueden parecer muy similares a las declaraciones If-Else, pero son funcionalmente diferentes.

En el siguiente código, hemos modificado nuestro factorial programa utilizando el concepto de guards.

fact :: Integer -> Integer 
fact n | n == 0 = 1 
       | n /= 0 = n * fact (n-1) 
main = do 
   putStrLn "The factorial of 5 is:"  
   print (fact 5)

Aquí, hemos declarado dos guards, separados por "|" y llamando alfact función de main. Internamente, el compilador funcionará de la misma manera que en el caso de la coincidencia de patrones para producir el siguiente resultado:

The factorial of 5 is:
120

Dónde cláusula

Wherees una palabra clave o función incorporada que se puede utilizar en tiempo de ejecución para generar una salida deseada. Puede resultar muy útil cuando el cálculo de funciones se vuelve complejo.

Considere un escenario donde su entrada es una expresión compleja con múltiples parámetros. En tales casos, puede dividir toda la expresión en partes pequeñas utilizando la cláusula "where".

En el siguiente ejemplo, tomamos una expresión matemática compleja. Mostraremos cómo se pueden encontrar las raíces de una ecuación polinomial [x ^ 2 - 8x + 6] usando Haskell.

roots :: (Float, Float, Float) -> (Float, Float)  
roots (a,b,c) = (x1, x2) where 
   x1 = e + sqrt d / (2 * a) 
   x2 = e - sqrt d / (2 * a) 
   d = b * b - 4 * a * c  
   e = - b / (2 * a)  
main = do 
   putStrLn "The roots of our Polynomial equation are:" 
   print (roots(1,-8,6))

Observe la complejidad de nuestra expresión para calcular las raíces de la función polinomial dada. Es bastante complejo. Por lo tanto, estamos rompiendo la expresión usando elwherecláusula. El fragmento de código anterior generará el siguiente resultado:

The roots of our Polynomial equation are:
(7.1622777,0.8377223)

Función de recursividad

La recursividad es una situación en la que una función se llama a sí misma repetidamente. Haskell no ofrece la posibilidad de realizar un bucle de expresión más de una vez. En cambio, Haskell quiere que divida toda su funcionalidad en una colección de funciones diferentes y use la técnica de recursividad para implementar su funcionalidad.

Consideremos nuestro ejemplo de coincidencia de patrones nuevamente, donde hemos calculado el factorial de un número. Encontrar el factorial de un número es un caso clásico de uso de recursividad. Aquí, podría, "¿En qué se diferencia la coincidencia de patrones de la recursividad?" La diferencia entre estos dos radica en la forma en que se utilizan: la coincidencia de patrones funciona en la configuración de la restricción del terminal, mientras que la recursividad es una llamada de función.

En el siguiente ejemplo, hemos utilizado tanto la coincidencia de patrones como la recursividad para calcular el factorial de 5.

fact :: Int -> Int 
fact 0 = 1 
fact n = n * fact ( n - 1 ) 

main = do 
   putStrLn "The factorial of 5 is:" 
   print (fact 5)

Producirá la siguiente salida:

The factorial of 5 is:
120

Función de orden superior

Hasta ahora, lo que hemos visto es que las funciones de Haskell toman una type como entrada y producir otro typecomo salida, que es bastante similar en otros lenguajes imperativos. Las funciones de orden superior son una característica única de Haskell donde puede utilizar una función como argumento de entrada o salida.

Aunque es un concepto virtual, pero en programas del mundo real, cada función que definimos en Haskell usa un mecanismo de orden superior para proporcionar resultados. Si tiene la oportunidad de examinar la función de biblioteca de Haskell, encontrará que la mayoría de las funciones de biblioteca se han escrito en un orden superior.

Tomemos un ejemplo en el que importaremos un mapa de funciones de orden superior incorporado y lo usaremos para implementar otra función de orden superior de acuerdo con nuestra elección.

import Data.Char  
import Prelude hiding (map) 

map :: (a -> b) -> [a] -> [b] 
map _ [] = [] 
map func (x : abc) = func x : map func abc  
main = print $ map toUpper "tutorialspoint.com"

En el ejemplo anterior, hemos utilizado el toUpper función de la clase de tipo Charpara convertir nuestra entrada en mayúsculas. Aquí, el método "mapa" toma una función como argumento y devuelve la salida requerida. Aquí está su salida:

sh-4.3$ ghc -O2 --make *.hs -o main -threaded -rtsopts
sh-4.3$ main
"TUTORIALSPOINT.COM"

Expresión Lambda

A veces tenemos que escribir una función que se usará solo una vez, durante toda la vida útil de una aplicación. Para hacer frente a este tipo de situaciones, los desarrolladores de Haskell utilizan otro bloque anónimo conocido comolambda expression o lambda function.

Una función sin una definición se llama función lambda. Una función lambda se indica con el carácter "\". Tomemos el siguiente ejemplo en el que aumentaremos el valor de entrada en 1 sin crear ninguna función.

main = do 
   putStrLn "The successor of 4 is:"  
   print ((\x -> x + 1) 4)

Aquí, hemos creado una función anónima que no tiene nombre. Toma el número entero 4 como argumento e imprime el valor de salida. Básicamente, estamos operando una función sin siquiera declararla correctamente. Esa es la belleza de las expresiones lambda.

Nuestra expresión lambda producirá la siguiente salida:

sh-4.3$ main
The successor of 4 is:
5