2012-08-26 22 views
5

Estoy tratando de establecer un esquema de autorización donde compruebo que 1. el usuario ha iniciado sesión 2. el usuario tiene acceso a un determinado objeto. Para esto, primero llamo al maybeAuthId, luego intento obtener el objeto actual y me uno a otra tabla que enumera los permisos. Hay dos niveles de may-cases y un nivel de caso de lista vacía. Pensé en usar MaybeT, pero o bien estoy demasiado cansado para hacerlo funcionar o el transformador "no realmente mónada", los manipuladores-transformadores no se pueden usar con MaybeT. ¿Hay una buena manera de manejar maybes profundos?Profundo puede apilarse con yesod

Editar:

que estaba un poco confuso lo que parece. Quiero decir que tengo algo como esto:

case foo of 
    Nothing -> something 
    Just foo' -> do 
     bar <- somethingelse 
     case bar of 
     Nothing -> ... 
     Just bar' -> ... 

Respuesta

6

Puede utilizar totalmente MaybeT para Yesod. Simplemente hazlo así:

runMaybeT $ do 
    uid <- MaybeT maybeAuthID 
    car <- MaybeT . runDB . getBy $ UniqueCarOwner uid 
    location <- MaybeT . liftIO . ciaLocateLicensePlate . licensePlate $ car 
    country <- MaybeT . findCountry $ location 
    return (car, country) 

Como dijiste, la mayoría de las funciones no están optimizadas para el manejo de errores genéricos en Yesod. Sin embargo, si tiene algo del formulario Monad m => m (Maybe a), simplemente puede usar MaybeT para convertirlo en Monad m => Maybe (m a).

+0

Gracias. Hace un tiempo desde que usé transformadores, y olvidé que necesito envolverlos en MaybeT. – Masse

1

No está muy claro qué quiere decir con "manejar maybes profundos", pero se puede usar monádico join (de Control.Monad) para eliminar un nivel de anidamiento a la vez.

ghci> :m +Control.Monad 
ghci> join (Just (Just 3)) 
Just 3 
ghci> join (Just Nothing) 
Nothing 
ghci> join Nothing 
Nothing 

Sin embargo, el uso de MaybeT es probablemente una mejor opción para su problema. Si aclaras lo que estás tratando de hacer, podemos ayudarte a formularlo con MaybeT.

2

Por lo que entiendo, las capas se ven como:

Maybe [Maybe r] 

... y que desea join los dos Maybe s juntos, pero la lista está en el camino. Este es precisamente el problema sequence resuelve:

sequence :: (Monad m) => [m r] -> m [r] 

Tenga en cuenta que si nos especializamos sequence a la Maybe mónada obtenemos:

sequence :: [Maybe r] -> Maybe [r] 

En este caso particular, sequence devolverá un Nothing si hay al menos uno Nothing en la lista, pero si son todos Just s, entonces los unirá a todos en un solo Just.

Todo lo que queda es para mapear sequence el exterior Maybe:

fmap sequence :: Maybe [Maybe r] -> Maybe (Maybe [r]) 

Ahora bien, esto es exactamente en la forma que necesitamos para unirse a:

join . fmap sequence :: Maybe [Maybe r] -> Maybe [r] 

Así que, intuitivamente, lo que la función anterior Lo que hace es que si todos los Maybe internos son Just sy el Maybe externo es Just, entonces se fusiona todo el resultado en un solo Just que contiene el lista. Sin embargo, si alguno Maybe (ya sea interno o externo) es Nothing, el resultado final es Nothing.

Observe que a pesar de hacer un montón de búsqueda de tipos ciegos, terminamos con una función que hace lo correcto de forma intuitiva. Este es el poder de las abstracciones basadas en la teoría de categorías.