Question

Si vous regardez l'exemple pour catches:

 f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex),
                     Handler (\ (ex :: IOException)    -> handleIO    ex)]

On dirait que catches a défini un mécanisme personnalisé pour correspondre à motifs (les deux types d'exception). Je me trompe, ou peut-il être généralisé pour permettre de définir une fonction qui peut prendre des fonctions lambda qui correspondent à un certain motif?

Edit: Pour votre information ci-dessous est la source GHC pour les prises. Si quelqu'un peut faire la lumière sur la façon dont cela fonctionne, il serait grand.

catches :: IO a -> [Handler a] -> IO a
catches io handlers = io `catch` catchesHandler handlers

catchesHandler :: [Handler a] -> SomeException -> IO a
catchesHandler handlers e = foldr tryHandler (throw e) handlers
    where tryHandler (Handler handler) res
              = case fromException e of
                Just e' -> handler e'
                Nothing -> res
Était-ce utile?

La solution

est Variables déclarées Type l'extension GHC au travail. Suivez le lien pour en savoir plus.

En fait, vous définissez une affirmation sur le type qui doivent être pris en charge par le crépitement avant qu'il ne puisse égaler. Alors, oui, il est semblable à des gardes, mais pas tout à fait.

Comment fonctionne cet exemple? Plongez dans pour savoir que:

class (Show e) => Exception e where
    toException   :: e -> SomeException
    fromException :: SomeException -> Maybe e

data SomeException = forall e . Exception e => SomeException e

instance Exception IOException where
    toException = IOException
    fromException (IOException e) = Just e
    fromException _ = Nothing

instance Exception ArithException where
    toException = ArithException
    fromException (ArithException e) = Just e
    fromException _ = Nothing

On voit que IOException et ArithException sont différents types d'application de la Exception de classe de types. On voit aussi que toException/fromException est un emballage / mécanisme déballant qui permet de convertir des valeurs de type Exception à / à partir des valeurs de types IOException, ArithException, etc.

Alors, on aurait pu écrire:

f = expr `catches` [Handler handleArith,
                    Handler handleIO]

handleArith :: ArithException -> IO ()
handleArith ex = ....

handleIO :: IOException -> IO ()
handleIO ex = ....

Supposons que IOException arrive. Lorsque catchesHandler traite premier élément de la liste des gestionnaires, il appelle tryHandler, qui appelle fromException. De la définition de tryHandler il suit ce type de retour de la fromException devrait être le même que l'argument de handleArith. D'autre part, e est de type Exception, à savoir - (IOException ...). Ainsi, les types jouent de cette façon (ce n'est pas valide haskell, mais j'espère que vous obtenez mon point):

fromException :: (IOException ...) -> Maybe ArithException

De l'instance Exception IOException ... il suit immédiatement que le résultat est Nothing, donc ce gestionnaire est sauté. Par le même raisonnement le gestionnaire suivant serait appelé, parce que fromException retournerait (Just (IOException ...)).

Alors, vous avez utilisé les signatures de type de handleArith et handleIO pour spécifier quand chacun d'entre eux seraient appelés, et fromException/toException fait en sorte qu'il est arrivé de cette façon.

Si vous le souhaitez, vous pouvez également contrainte de types handleIO et handleArith dans la définition de f, en utilisant des variables de type scope. On peut dire que, cela pourrait vous donner une meilleure lisibilité.

Finaliser, Variables déclarées de type ne sont pas un joueur primaire ici. Ils sont juste utilisés pour plus de commodité. Les machines principales pour jouer ce genre de trucs est fromException/toException et les amis. Variables de type scope simplement vous permettre d'avoir une syntaxe qui ressemblent plus étroitement les modèles de garde.

Autres conseils

case () of 
  ()| foo expr1 -> handleFooCase
    | bar expr2 -> handleBarCase
    | otherwise -> blah
scroll top