2010-06-13 15 views
10

La función de búsqueda en Data.Map y Data.IntMap valores envueltos en la actualidad Tal vez volver con la firma de tipomapas Haskell que regresan una mónada

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

Se solía tener el tipo más general de

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

Me doy cuenta de que el primero probablemente reduce la necesidad de especificación de tipo adicional, pero esto último lo haría mucho más general y permitiría que la búsqueda se usara en la lista de comprensiones. ¿Hay alguna manera de imitar este comportamiento con la versión más nueva, o tendría que usar una versión anterior de la biblioteca?

Respuesta

5

de don lift convierte elementos Maybe 's a sus generales Monad homólogos, así que quizás debería llamarse convert o generalize o algo ;-)

Si lo que desea es utilizar lookup principalmente en las listas por comprensión y otras mónadas que implementan una fail, también se puede hacer uso de la asignación de la falta de coincidencia de patrones 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

Esto ilustra perfectamente por qué el uso del error es malo: casi siempre es una excepción de finalización del programa. No es lo que quieres cuando buscas en los mapas. –

+0

Bueno, dije "mónadas que implementan un error", ¿verdad? -) 'error' no está definido no está implementado. Solo quería ilustrar ese caso también. Personalmente, utilizo el patrón match failure en do-blocks cuando la mónada también es un 'MonadPlus' e implementa' fail' como 'mzero'. Entonces es cuando esta técnica es más útil. – claus

19

este último haría mucho más general y permitir operaciones de búsqueda que se utiliza en las listas por comprensión

Este último también es más insegura, ya que la mayoría de las clases monad definir fallar como error. Es decir, el caso común de no encontrar un elemento en el Mapa es un error de terminación del programa para la mayoría de las mónadas. Eso, junto con la mayor probabilidad de inferir el contexto de tipo incorrecto, significa que ahora tendemos a desalentar el estilo de 'retorno monofónico fallido'.

¿Hay alguna manera de imitar este comportamiento con la versión más reciente

De hecho hay! Simplemente levante Maybe a into Monad a, así:

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

Y ahora puede escribir, p. lift . lookup

+0

Gracias por la respuesta rápida Don. Eso es mucho más conciso de lo que se me ocurrió. – sabauma

+0

Podría tener sentido considerar actualizar esta respuesta una vez que salga la próxima versión principal de 'base'. Parece que 'fail' finalmente está dejando' Monad', quizás aterrizando en un nuevo 'MonadFail'. – dfeuer

4

para los cas específicas e de la lista de mónada, la solución más simple es usar 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"] 
Cuestiones relacionadas