2012-06-19 13 views
9

Ho il seguente codice, e penso che è brutto:Semplificare espressioni Forse

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")] 

Questo codice sembra essere molto imperativo. Posso semplificarlo in qualche modo?

risposta

9

Come altri hanno suggerito, Applicative potrebbe essere bello qui, così come MaybeT a seconda del contesto. Una terza cosa da tenere a mente è che un errore di corrispondenza del modello in un blocco do chiama il numero fail.

Questo è quello che vorrei fare:

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

o una soluzione con MaybeT, anche se uno con un valore di ritorno diverso (di nuovo più contesto potrebbe mostrare che questo è un buon approccio 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")]) 

... in realtà quanto sopra è piuttosto hokey, ora che lo guardo

+1

Penso che il tuo primo approccio sia il più pulito del lotto. Questo è quello che farei comunque :). –

+2

+1 quando ho visto il tipo di logica richiesta, ho immediatamente pensato a 'fromMaybe' + applicative. La tua soluzione 'fromMaybe' è molto pulita. La soluzione di MaybeT non è male; il refactoring di ampie porzioni di codice per utilizzare MaybeT potrebbe essere una buona scelta nel caso dell'OP. –

12

ne dite:

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")] 

codice che utilizza isJust e/o fromJust è quasi sempre cattivo stile e un po 'pericoloso se si ottiene il controllo isJust prima fromJust sbagliato.

Questo può essere essere migliorata

  • pattern matching, come sopra. Ma se questo è annidato diventa brutto.
  • Gli abbinatori, come da Mayay, possono essere più concisi.
  • L'uso di Maybe (e MaybeT) come Applicative o Monad può evitare il brutto nidificazione.
4
loginCheck = case (,) <$> getPostParam "login" <*> getPostParam "password" of 
    Just (l, p) -> authAs l p 
    Nothing  -> render "Msg" [("text", "Form incomplete")] 

forse? 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")] 

Quanto è fastidioso.

+0

Re vostra seconda atte mpt: Penso che 'x :: (Forse ByteString, Maybe ByteString)', non 'x :: Maybe (ByteString, ByteString)'. Il funzionamento del '<$>' e '<*>' sta funzionando su 'IO', non' Maybe'. – dave4420

+0

Deve solo aggiungere liftM2 prima del caso: 'liftM2 (,) <$> getPostParam" login "<*> getPostParam" password ">> = \ res -> caso res di ...' – applicative

2

Non so se questo è un miglioramento qui, ma forse in alcuni casi ...

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

Penso che sia più pulito non definire 'rendering ' 'e' authAs'', e basta scrivere il 'lift's in linea, perché in genere una tale funzione non verrebbe utilizzata più di una volta. –

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

questo potrebbe sembrare strano, perché pattern corrisponde a un Maybe (IO()), ma questo è perfettamente sana. Oppure, utilizzando maybe:

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

Oh, ho dimenticato 'daMaybe' menzionato da' jberryman'; dove uso 'forse' dovrebbe essere solo' fromMebe 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