2012-06-19 3 views
9

У меня есть следующий код, и я думаю, что это некрасиво:Simplify Может выражение

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

Этот код кажется очень важно. Могу ли я это упростить?

ответ

9

Как и другие предложили, Applicative может быть приятно здесь, а также MaybeT в зависимости от контекста. Третья вещь, которую вы можете иметь в виду, это то, что ошибка совпадения шаблона в блоке связывания .

Это то, что я хотел бы сделать:

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

Или решение с MaybeT, хотя и с другим значением возврата (опять больше контекста может показать, что это хороший подход, или нет):

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

... на самом деле выше, а фальшивый теперь, когда я смотрю на него

+1

Я думаю, что ваш первый подход - самый чистый из партии. Это то, что я бы сделал, так или иначе :). –

+2

+1 Когда я увидел требуемый тип логики, я сразу же подумал, что «от Майкла» + аппликации. Решение 'fromMaybe' очень чистое. Решение MaybeT неплохое; рефакторинг больших рядов кода для использования MaybeT может быть хорошим выбором в случае OP. –

12

Как насчет:

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

код, который использует isJust и/или fromJust почти всегда плохой стиль и немного опасно, если вы получите чек isJust до fromJust неправильно.

Это может быть быть улучшена за счет

  • сопоставления с образцом, как и выше. Но если это вложен, он становится уродливым.
  • Комбинаторы, как и от мая, могут быть более краткими.
  • Использование Maybe (и MaybeT) в качестве аппликативного или монады может избежать уродливого гнездования.
4
loginCheck = case (,) <$> getPostParam "login" <*> getPostParam "password" of 
    Just (l, p) -> authAs l p 
    Nothing  -> render "Msg" [("text", "Form incomplete")] 

возможно? Нет. К сожалению.

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

Как досадно.

+0

Re ваш второй Atte mpt: Я думаю, что 'x :: (Может быть, ByteString, Maybe ByteString)', а не 'x :: Maybe (ByteString, ByteString)'. Функтор '<$>' и '<*>' работают на 'IO', а не' Maybe'. – dave4420

+0

Ему просто нужно добавить liftM2 перед футляром: 'liftM2 (,) <$> getPostParam« login »<*> getPostParam« password »>> = \ res -> case res of ...' – applicative

2

Не уверен, если это улучшение здесь, но, возможно, в некоторых случаях ...

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

Я думаю, что более чистое не определять 'render ' 'и' authAs'', и просто напишите 'lift's inline, потому что такая функция обычно не будет использоваться более одного раза в любом случае. –

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

Это может показаться странным, поскольку он соответствует шаблону на Maybe (IO()), но это совершенно доброкачественной. Или, используя maybe:

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

О, забыл о 'fromMaybe', упомянутом' jberryman'; где я использую 'возможно', это должно быть просто' 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  
Смежные вопросы