Haskell - Fonctions

Les fonctions jouent un rôle majeur dans Haskell, car il s'agit d'un langage de programmation fonctionnel. Comme les autres langages, Haskell a sa propre définition fonctionnelle et sa propre déclaration.

  • La déclaration de fonction se compose du nom de la fonction et de sa liste d'arguments ainsi que de sa sortie.

  • La définition de fonction est l'endroit où vous définissez réellement une fonction.

Prenons un petit exemple de add fonction pour comprendre ce concept en détail.

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

Ici, nous avons déclaré notre fonction dans la première ligne et dans la deuxième ligne, nous avons écrit notre fonction réelle qui prendra deux arguments et produira une sortie de type entier.

Comme la plupart des autres langages, Haskell commence à compiler le code à partir du mainméthode. Notre code générera la sortie suivante -

The addition of the two numbers is:
7

Correspondance de motif

La correspondance de modèles est un processus de correspondance de types d'expressions spécifiques. Ce n'est rien d'autre qu'une technique pour simplifier votre code. Cette technique peut être implémentée dans n'importe quel type de classe Type. If-Else peut être utilisé comme une option alternative de correspondance de modèle.

Le Pattern Matching peut être considéré comme une variante du polymorphisme dynamique où, à l'exécution, différentes méthodes peuvent être exécutées en fonction de leur liste d'arguments.

Jetez un œil au bloc de code suivant. Ici, nous avons utilisé la technique du Pattern Matching pour calculer la factorielle d'un nombre.

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

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

Nous savons tous comment calculer la factorielle d'un nombre. Le compilateur commencera à rechercher une fonction appelée "fact" avec un argument. Si l'argument n'est pas égal à 0, alors le nombre continuera d'appeler la même fonction avec 1 de moins que celui de l'argument réel.

Lorsque le modèle de l'argument correspond exactement à 0, il appellera notre modèle qui est "fait 0 = 1". Notre code produira la sortie suivante -

The factorial of 5 is:
120

Gardes

Guardsest un concept très similaire à la correspondance de modèles. Dans la correspondance de modèles, nous faisons généralement correspondre une ou plusieurs expressions, mais nous utilisonsguards pour tester une propriété d'une expression.

Bien qu'il soit conseillé d'utiliser la correspondance de motifs sur guards, mais du point de vue du développeur, guardsest plus lisible et simple. Pour les nouveaux utilisateurs,guards peuvent ressembler beaucoup aux instructions If-Else, mais elles sont fonctionnellement différentes.

Dans le code suivant, nous avons modifié notre factorial programme en utilisant le concept 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)

Ici, nous avons déclaré deux guards, séparés par "|" et appeler lefact fonction de main. En interne, le compilateur fonctionnera de la même manière que dans le cas de la correspondance de modèles pour produire la sortie suivante -

The factorial of 5 is:
120

Clause Où

Whereest un mot-clé ou une fonction intégrée qui peut être utilisée lors de l'exécution pour générer une sortie souhaitée. Cela peut être très utile lorsque le calcul de la fonction devient complexe.

Considérez un scénario dans lequel votre entrée est une expression complexe avec plusieurs paramètres. Dans de tels cas, vous pouvez diviser l'expression entière en petites parties à l'aide de la clause "where".

Dans l'exemple suivant, nous prenons une expression mathématique complexe. Nous montrerons comment trouver les racines d'une équation polynomiale [x ^ 2 - 8x + 6] en utilisant 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))

Notez la complexité de notre expression pour calculer les racines de la fonction polynomiale donnée. C'est assez complexe. Par conséquent, nous cassons l'expression en utilisant lewhereclause. Le morceau de code ci-dessus générera la sortie suivante -

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

Fonction de récursivité

La récursivité est une situation dans laquelle une fonction s'appelle elle-même à plusieurs reprises. Haskell ne fournit aucune possibilité de boucler une expression plus d'une fois. Au lieu de cela, Haskell souhaite que vous divisiez l'ensemble de vos fonctionnalités en un ensemble de fonctions différentes et que vous utilisiez une technique de récursivité pour implémenter votre fonctionnalité.

Considérons à nouveau notre exemple de correspondance de motifs, où nous avons calculé la factorielle d'un nombre. Trouver la factorielle d'un nombre est un cas classique d'utilisation de la récursivité. Ici, vous pourriez, "En quoi la correspondance de modèle est-elle différente de la récursivité?" La différence entre ces deux réside dans la manière dont ils sont utilisés.

Dans l'exemple suivant, nous avons utilisé à la fois la correspondance de modèle et la récursivité pour calculer la factorielle 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)

Il produira la sortie suivante -

The factorial of 5 is:
120

Fonction d'ordre supérieur

Jusqu'à présent, ce que nous avons vu, c'est que les fonctions Haskell en prennent une type comme intrant et produire un autre typeen sortie, ce qui est assez similaire dans d'autres langages impératifs. Les fonctions d'ordre supérieur sont une fonctionnalité unique de Haskell où vous pouvez utiliser une fonction comme argument d'entrée ou de sortie.

Bien que ce soit un concept virtuel, mais dans les programmes du monde réel, chaque fonction que nous définissons dans Haskell utilise un mécanisme d'ordre supérieur pour fournir une sortie. Si vous avez une chance de regarder dans la fonction de bibliothèque de Haskell, alors vous constaterez que la plupart des fonctions de bibliothèque ont été écrites dans un ordre supérieur.

Prenons un exemple où nous allons importer une carte de fonctions d'ordre supérieur intégrée et l'utiliser pour implémenter une autre fonction d'ordre supérieur selon notre choix.

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"

Dans l'exemple ci-dessus, nous avons utilisé le toUpper fonction de la classe de type Charpour convertir notre entrée en majuscules. Ici, la méthode "map" prend une fonction comme argument et renvoie la sortie requise. Voici sa sortie -

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

Expression Lambda

Nous devons parfois écrire une fonction qui ne sera utilisée qu'une seule fois, pendant toute la durée de vie d'une application. Pour faire face à ce genre de situation, les développeurs Haskell utilisent un autre bloc anonyme appelélambda expression ou lambda function.

Une fonction sans définition est appelée une fonction lambda. Une fonction lambda est désignée par le caractère "\". Prenons l'exemple suivant où nous allons augmenter la valeur d'entrée de 1 sans créer de fonction.

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

Ici, nous avons créé une fonction anonyme qui n'a pas de nom. Il prend l'entier 4 comme argument et imprime la valeur de sortie. Nous exploitons essentiellement une fonction sans même la déclarer correctement. C'est la beauté des expressions lambda.

Notre expression lambda produira la sortie suivante -

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