Je passe par Learn you a haskell book, et au chapitre 8 il y a un extrait de code qui ressemble à ceci
data LockerState = Taken | Free deriving (Eq, Show)
type Code = String
type LockerMap = Map.Map Int (LockerState, Code)
lookup' :: Int -> LockerMap -> Either String Code
lookup' num_ map_ =
case (Map.lookup num_ map_) of
Nothing -> Left $ "LockerNumber doesn't exist!"
Just (state, code) -> if state == Taken
then Left $ "LockerNumber already taken!"
else Right $ code
Cela marche. Cependant, je voulais convertir le bloc if/else pour garder des instructions comme ceci:
lookup' :: Int -> LockerMap -> Either String Code
lookup' num_ map_ =
case (Map.lookup num_ map_) of
Nothing -> Left $ "LockerNumber doesn't exist!"
Just (state, code) ->
| state == Taken = Left $ "LockerNumber already taken!"
| otherwise = Right $ Code
Cela ne compile pas. Il semble que l'utilisation des gardes dans Haskell soit très restrictive/non intuitive. SO Ex1SO Ex2 . Y a-t-il une source précise que je peux lire qui indique à quels endroits je peux utiliser des gardes?
Les gardes sont autorisées à deux endroits: les définitions de fonction et les expressions case
. Dans les deux contextes, les gardes apparaissent après un motif et avant le corps, vous utilisez donc =
dans les fonctions et ->
dans case
branches, comme d'habitude:
divide x y
| y == 0 = Nothing
--------
| otherwise = Just (x / y)
-----------
positively mx = case mx of
Just x | x > 0 -> Just x
-------
_ -> Nothing
Les gardes sont simplement des contraintes pour les motifs, donc Just x
correspond à toute valeur nonNothing
, mais Just x | x > 0
ne correspond qu'à un Just
dont la valeur encapsulée est également positive.
Je suppose que la référence définitive est le Rapport Haskell , en particulier les expressions de cas §3.13 et les liaisons de fonctions et de motifs §4.4.3, qui décrivent la syntaxe des gardes et spécifient où elles sont autorisées.
Dans votre code, vous souhaitez:
Just (state, code)
| state == Taken -> Left "LockerNumber already taken!"
| otherwise -> Right code
Ceci est également exprimable avec des motifs seuls:
Just (Taken, _) -> Left "LockerNumber already taken!"
Just (_, code) -> Right code