2010-06-13 9 views
10

La fonction de recherche dans Data.Map et Data.IntMap retour en valeurs enveloppées dans Peut-être avec la signature de typecartes Haskell retour une monade

lookup :: Ord k => k -> Map k a -> Maybe a 

Il l'habitude d'avoir le type plus général de

lookup :: (Monad m, Ord k) => k -> Map k a -> m a 

Je réalise que le premier réduit probablement le besoin de spécification de type supplémentaire, mais le second le rendrait beaucoup plus général et permettrait d'utiliser la recherche dans les listes de compréhension. Est-il possible d'imiter ce comportement avec la version plus récente, ou devrais-je utiliser une ancienne version de la bibliothèque?

Répondre

5

Don de lift convertit les éléments de Maybe à leurs Monad généraux homologues, alors peut-être il devrait être nommé convert ou generalize ou quelque chose ;-)

Si vous voulez juste utiliser lookup principalement dans compréhensions de liste et d'autres monades qui mettent en œuvre un fail, vous pouvez également utiliser la cartographie de l'échec de correspondance de motif à fail:

 
Prelude> [ v | Just v <- return $ lookup "hi" [("ho","silver")] ] 
[] 
Prelude> [ v | Just v <- return $ lookup "ho" [("ho","silver")] ] 
["silver"] 

Prelude> do Just v <- return $ lookup "hi" [("ho","silver")] ; print v 
*** Exception: user error (Pattern match failure in do expression at <interactive>:1:3-8) 
Prelude> do Just v <- return $ lookup "ho" [("ho","silver")] ; print v 
"silver" 
+1

Ceci illustre parfaitement pourquoi l'utilisation de fail est mauvaise: il s'agit presque toujours d'une exception de terminaison de programme. Pas ce que vous voulez en regardant dans les cartes. –

+0

Eh bien, j'ai dit "monades qui implémentent un échec", n'est-ce pas? -) 'error' est indéfini n'est pas mis en œuvre. Je voulais juste illustrer ce cas aussi. Personnellement, j'utilise l'échec de correspondance de modèle dans do-blocks lorsque la monade est aussi un 'MonadPlus' et implémente' fail' comme 'mzero'. C'est quand cette technique est la plus utile. – claus

19

ce dernier serait beaucoup plus générale et permettre recherche à utiliser dans la liste compréhensions

Ce dernier est aussi plus dangereuse, car la majorité des classes de monades définissent comme error échouent. C'est-à-dire que le cas courant de ne pas trouver un élément dans la carte est une erreur de terminaison de programme pour la plupart des monades. Cela, couplé avec la probabilité accrue d'un contexte de type erroné étant déduit, signifie que nous avons tendance à décourager le style «monadic fail return» maintenant.

Est-il possible d'imiter ce comportement avec la nouvelle version

Il y a en effet! Il suffit de soulever Peut-être un dans Monad un, comme ceci:

lift :: Monad m => Maybe a -> m a 
lift Nothing = fail "you die now" 
lift (Just a) = return a 

Et vous pouvez maintenant écrire, par exemple lift . lookup

+0

Merci pour la réponse rapide Don. C'est beaucoup plus concis que ce que j'ai trouvé. – sabauma

+0

Il peut être judicieux d'envisager de mettre à jour cette réponse une fois que la prochaine version majeure de 'base' sera disponible. Il semble que 'fail 'quitte finalement' Monad', peut-être atterrissant dans un nouveau 'MonadFail'. – dfeuer

4

pour les particuliers CAS e de la liste monad, la solution la plus simple est d'utiliser maybeToList:

Prelude> :m +Data.Maybe -- Note: Use "import Data.Maybe" in a program file 

Data.Maybe> [ v | v <- maybeToList $ lookup "hi" [("ho","silver")] ] 
[] 
Data.Maybe> [ v | v <- maybeToList $ lookup "ho" [("ho","silver")] ] 
["silver"]