web-dev-qa-db-fra.com

Haskell - Déclaration de garde à l'intérieur du boîtier

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?

18
skgbanga

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
45
Jon Purdy