Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplify Maybe expressions

Tags:

haskell

I have the following code, and I think it is ugly:

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

This code seems to be very imperative. Can I simplify it somehow?

like image 779
demi Avatar asked Jun 19 '12 20:06

demi


People also ask

What is a simplified expression example?

For example, 1/2 (x + 4) can be simplified as x/2 + 2. Let us take one more example to understand it. Example: Simplify the expression: 3/4x + y/2 (4x + 7). By using the distributive property, the given expression can be written as 3/4x + y/2 (4x) + y/2 (7).

What is simplest expression?

In general, an expression is in simplest form when it is easiest to use. Example, this: 5x + x − 3.


6 Answers

How about:

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

Code that uses isJust and/or fromJust is nearly always bad style and slightly dangerous if you get the isJust check before fromJust wrong.

This can be be improved by

  • Pattern matching, like above. But if this is nested it gets ugly.
  • Combinators, like fromMaybe can be more succinct.
  • Using Maybe (and MaybeT) as Applicative or a Monad can avoid the ugly nesting.
like image 133
Chris Kuklewicz Avatar answered Oct 05 '22 01:10

Chris Kuklewicz


As others have suggested, Applicative could be nice here, as well as MaybeT depending on the context. A third thing you might keep in mind is that a pattern match failure in a do block binding calls fail.

This is what I would do:

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

Or a solution with MaybeT, albeit one with a different return value (again more context might show this to be a good approach or not):

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

...actually the above is rather hokey now that I look at it

like image 20
jberryman Avatar answered Oct 05 '22 03:10

jberryman


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

perhaps? 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.

like image 40
pigworker Avatar answered Oct 05 '22 03:10

pigworker


Not sure if this is an improvement here, but maybe in some cases...

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
like image 44
FunctorSalad Avatar answered Oct 05 '22 02:10

FunctorSalad


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

This might seem strange because it pattern matches on a Maybe (IO ()), but this is perfectly sound. Or, using maybe:

loginCheque = mapM getPostParam ["login","password"] >>= \[ml,mp] -> 
              maybe message id (liftM2 authAs ml mp)
    where message = render "Msg" [("text", "Form incomplete")]
like image 26
applicative Avatar answered Oct 05 '22 03:10

applicative


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       
like image 42
ja. Avatar answered Oct 05 '22 01:10

ja.