Haskell Language
Syntaxe dans les fonctions
Recherche…
Gardes
Une fonction peut être définie à l'aide de gardes, qui peuvent être considérés comme classant le comportement en fonction de l'entrée.
Prenez la définition de fonction suivante:
absolute :: Int -> Int -- definition restricted to Ints for simplicity
absolute n = if (n < 0) then (-n) else n
Nous pouvons le réorganiser en utilisant des gardes:
absolute :: Int -> Int
absolute n
| n < 0 = -n
| otherwise = n
Dans ce contexte, otherwise
est un alias significatif pour True
, donc il devrait toujours être le dernier gardien.
Correspondance de motif
Haskell prend en charge les expressions de correspondance de modèle à la fois dans la définition des fonctions et dans les déclarations de case
.
Une instruction de cas ressemble beaucoup à un commutateur dans d'autres langues, sauf qu'elle prend en charge tous les types de Haskell.
Commençons simple:
longName :: String -> String
longName name = case name of
"Alex" -> "Alexander"
"Jenny" -> "Jennifer"
_ -> "Unknown" -- the "default" case, if you like
Ou, nous pourrions définir notre fonction comme une équation qui serait une correspondance de modèle, sans utiliser une déclaration de case
:
longName "Alex" = "Alexander"
longName "Jenny" = "Jennifer"
longName _ = "Unknown"
Un exemple plus courant concerne le type Maybe
:
data Person = Person { name :: String, petName :: (Maybe String) }
hasPet :: Person -> Bool
hasPet (Person _ Nothing) = False
hasPet _ = True -- Maybe can only take `Just a` or `Nothing`, so this wildcard suffices
La correspondance de modèle peut également être utilisée sur des listes:
isEmptyList :: [a] -> Bool
isEmptyList [] = True
isEmptyList _ = False
addFirstTwoItems :: [Int] -> [Int]
addFirstTwoItems [] = []
addFirstTwoItems (x:[]) = [x]
addFirstTwoItems (x:y:ys) = (x + y) : ys
En fait, la correspondance de modèle peut être utilisée sur n'importe quel constructeur pour n'importe quelle classe de type. Par exemple, le constructeur des listes est :
et pour les tuples ,
En utilisant où et les gardes
Compte tenu de cette fonction:
annualSalaryCalc :: (RealFloat a) => a -> a -> String
annualSalaryCalc hourlyRate weekHoursOfWork
| hourlyRate * (weekHoursOfWork * 52) <= 40000 = "Poor child, try to get another job"
| hourlyRate * (weekHoursOfWork * 52) <= 120000 = "Money, Money, Money!"
| hourlyRate * (weekHoursOfWork * 52) <= 200000 = "Ri¢hie Ri¢h"
| otherwise = "Hello Elon Musk!"
Nous pouvons utiliser where
éviter la répétition et rendre notre code plus lisible. Voir la fonction alternative ci-dessous, en utilisant where
:
annualSalaryCalc' :: (RealFloat a) => a -> a -> String
annualSalaryCalc' hourlyRate weekHoursOfWork
| annualSalary <= smallSalary = "Poor child, try to get another job"
| annualSalary <= mediumSalary = "Money, Money, Money!"
| annualSalary <= highSalary = "Ri¢hie Ri¢h"
| otherwise = "Hello Elon Musk!"
where
annualSalary = hourlyRate * (weekHoursOfWork * 52)
(smallSalary, mediumSalary, highSalary) = (40000, 120000, 200000)
Comme l'a observé, nous avons utilisé le where
à la fin du corps de la fonction éliminant la répétition du calcul ( hourlyRate * (weekHoursOfWork * 52)
) et nous avons également utilisé where
d'organiser l'échelle salariale.
La dénomination des sous-expressions communes peut également être obtenue avec let
expressions let
, mais uniquement la syntaxe where
permet aux gardes de faire référence à ces sous-expressions nommées.