2012-06-19 15 views
9

tengo el siguiente código, y creo que es feo:simplificar las expresiones Tal

loginCheck = do 
    ml <- getPostParam "login" -- ml and mp :: Maybe ByteString 
    mp <- getPostParam "password" 
    if isJust ml && isJust mp 
    then authAs (fromJust ml) (fromJust mp) 
    else render "Msg" [("text", "Form incomplete")] 

Este código parece ser muy imprescindible. ¿Puedo simplificarlo de alguna manera?

Respuesta

9

Como otros han sugerido, Applicative podría ser agradable aquí, así como MaybeT dependiendo del contexto. Una tercera cosa que debe tener en cuenta es que una falla de coincidencia de patrón en un enlace de bloque do llama al fail.

Esto es lo que haría:

loginCheck = do 
    ml <- getPostParam "login" 
    mp <- getPostParam "password" 
    fromMaybe (render "Msg" [("text", "Form incomplete")]) $ 
      authAs <$> ml <*> mp 

o una solución con MaybeT, aunque con un valor de retorno diferente (otra vez más contexto podría mostrar que esto es un buen enfoque o no):

getPostParamT = MaybeT . getPostParam 
loginCheckT = do 
    ml <- getPostParamT "login" -- ml and mp :: Maybe ByteString 
    mp <- getPostParamT "password" 
    liftIO $ authAs ml mp 
    <|> (liftIO $ render "Msg" [("text", "Form incomplete")]) 

... en realidad lo anterior es bastante hokey ahora que lo miro

+1

Creo que su primer enfoque es el más limpio del lote. Eso es lo que haría, de todos modos :). –

+2

+1 cuando vi el tipo de lógica requerida, inmediatamente pensé 'fromMaybe' + applicatives. Su solución 'fromMaybe' es muy limpia. La solución MaybeT no está mal; refactorizar grandes franjas de código para usar MaybeT podría ser una buena opción en el caso de OP. –

12

¿Qué tal:

Código
loginCheck = do 
    ml <- getPostParam "login" -- ml and mp :: Maybe ByteString 
    mp <- getPostParam "password" 
    case (ml,mp) of 
    (Just l, Just p) -> authAs l p 
    _ -> render "Msg" [("text", "Form incomplete")] 

que utiliza isjust y/o fromJust es casi siempre mal estilo y un poco peligroso si se obtiene la verificación isjust antes fromJust mal.

esto se puede mejorar mediante

  • La concordancia de patrones, como anteriormente. Pero si esto está anidado, se pone feo.
  • Combinators, como fromMaybe pueden ser más concisos.
  • Usar Maybe (y MaybeT) como Applicative o una mónada puede evitar el feo anidamiento.
4
loginCheck = case (,) <$> getPostParam "login" <*> getPostParam "password" of 
    Just (l, p) -> authAs l p 
    Nothing  -> render "Msg" [("text", "Form incomplete")] 

tal vez? No. Oops.

loginCheck = do 
    x <- (,) <$> getPostParam "login" <*> getPostParam "password" of 
    case x of 
    Just (l, p) -> authAs l p 
    Nothing  -> render "Msg" [("text", "Form incomplete")] 

How annoying.

+0

Re su segundo atte mpt: creo 'x :: (Maybe ByteString, Maybe ByteString)', no 'x :: Maybe (ByteString, ByteString)'. El controlador '<$>' y '<*>' están operando en 'IO', no' Maybe'. – dave4420

+0

Solo necesita agregar liftM2 antes de la caja: 'liftM2 (,) <$> getPostParam" login "<*> getPostParam" password ">> = \ res -> case res de ...' – applicative

2

No estoy seguro si esto es una mejora aquí, pero tal vez en algunos casos ...

import Control.Monad 
import Control.Monad.Trans.Class 
import Control.Monad.Trans.Maybe 

getPostParam' = MaybeT . getPostParam 
render' x y = lift (render x y) 
authAs' x y = lift (authAs x y) 

loginCheck = runMaybeT $ 
     go `mplus` render' "Msg" [("text", "Form incomplete")] 
    where 
     go = do 
      ml <- getPostParam' "login" 
      mp <- getPostParam' "password" 
      authAs' ml mp 
+1

Creo que es más limpio no definir 'render ' 'y' authAs'', y simplemente escriba 'lift's inline, porque dicha función generalmente no se usará más de una vez. –

2
loginCheck = do 
    [ml,mp] <- mapM getPostParam ["login","password"] 
    case liftM2 authAs ml mp of 
    Nothing   -> render "Msg" [("text", "Form incomplete")] 
    Just authorize -> authorize 

Esto puede parecer extraño, ya que coincide con el patrón en un Maybe (IO()), pero esto es perfectamente sano. O, usando maybe:

loginCheque = mapM getPostParam ["login","password"] >>= \[ml,mp] -> 
       maybe message id (liftM2 authAs ml mp) 
    where message = render "Msg" [("text", "Form incomplete")] 
+0

Ah, se olvidó de 'fromMaybe' mencionado por' jberryman'; donde uso 'quizás' debería ser' fromMaybe message (liftM2 authAs ...) ' – applicative

1
loginCheck = do 
    res <- return$ getPostParam "login" >>= \l -> -- ml and mp :: Maybe ByteString 
        getPostParam "password" >>= \p-> 
        Just (l,p) 
    case res of Nothing -> render "Msg" [("text", "Form incomplete")] 
       (Just (l,p)) -> authAs l p  
Cuestiones relacionadas