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.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow