Search code examples
haskellmonadshaskell-snap-framework

Simplify Haskell Code


I'm working on Haskell code in the Snap framework. Everything works but now I need to clean up some code. However, after a few attempts, it seems I just have more code. Maybe anyone can give me some pointers?

This was my initial code. The thing is, I pattern match against a Maybe value which seems to me is very wrong. So I wanted to get that out of the way. But then the next line would get a Maybe value so I had to change that..

handleNewUserPost :: Handler App (AuthManager App) ()
handleNewUserPost = do
    Just username <- getPostParam "login"
    exists <- usernameExists $ T.decodeUtf8 username
    case exists of
        True    -> handleNewUserGet $ Just "Sorry, this username already exist."
        False   -> do
            registerUser "login" "password"
            redirect "/new_user"

Eventually I came to this:

handleNewUserPost :: Handler App (AuthManager App) ()
handleNewUserPost = do
    username <- getPostParam "login" -- :t username = Maybe ByteString
    validate username
    where 
      validate Nothing = redirect "/new_user"
      validate (Just username) = do exists <- existcheck username
                                    if exists
                                      then userexists
                                      else register
      existcheck :: C.ByteString -> Handler b (AuthManager b) Bool
      existcheck username = (usernameExists . T.decodeUtf8) $ username
      userexists          =  handleNewUserGet $ Just "Sorry, this username already exist."
      register            = do registerUser "login" "password"
                               redirect "/new_user"

The problem with this is that I have a feeling I shouldn't do a pattern match against the Nothing either. I'm in a do, so there should be something here. And the other thing is, I have a do in register as well. Any pointers are appreciated.


Solution

  • There's nothing wrong with your new code. Part of the reason that it's longer than the original is that you are handling the Nothing case, which you weren't doing originally (so your new code is safer). If you wanted to neaten it up a bit, you could write it as

    handleNewUserPost :: Handler App (AuthManager App) ()
    handleNewUserPost =
      getPostParam "login" >>= maybe (redirect "/new_user") validateUser
     where
      validateUser username = do
        exists <- usernameExists $ T.decodeUtf8 username
        if exists
          then handerNewUserGet $ Just "Sorry, this username already exists."
          else do
            registerUser "login" "password"
            redirect "/new_user"
    

    where I've used the function maybe from Data.Maybe to remove the need to explicitly handle the Just or Nothing values. This function is just defined as

    maybe :: b -> (a -> b) -> Maybe a -> b
    maybe b _ Nothing  = b
    maybe _ f (Just a) = f a