Функция похожа на когда, но возвращает значение?

Есть ли способ написать это более кратко? У меня есть много функций, которые выглядят так. У каждого из них есть некоторое логическое условие, которое либо возвращает значение, либо Nothing

rootMiddleware :: Application -> Application
rootMiddleware app req respond =
    fromMaybe next . fmap respond $
          serveIndex ["questionnaire"] "../app/answer/answer.html" req
      <|> serveIndex ["survey"] "../app/builder/builder.html" req
      <|> redirect [] "/survey/forms" req

  where
    next = app req respond

serveIndex :: [Text] -> FilePath -> Request -> Maybe Response
serveIndex prefix fp req =
    if prefix `isPrefixOf` pathInfo req
      then Just $ responseFile status200 [("Content-Type", "text/html")] fp Nothing
      else Nothing

redirect :: [Text] -> ByteString -> Request -> Maybe Response
redirect pathParts url req =
    if pathParts == pathInfo req
      then Just $ redirectTo url
      else Nothing

when действительно близко, но это не позволяет вам вернуть значение в аппликативе. Есть ли что-то эквивалентное для этого случая?


person Sean Clark Hess    schedule 26.10.2015    source источник
comment
Мне это уже кажется довольно кратким, вы можете использовать bool :: Bool -> a -> a -> a вместо if .. then .. else, если вы находите это более привлекательным.   -  person cdk    schedule 26.10.2015


Ответы (1)


Похоже, вы ищете guard:

guard :: Alternative f => Bool -> f ()
guard c = if c then pure () else empty

Затем вы можете переписать

if c then Just x else Nothing

as

x <$ guard c

Если вы не идете прямо к Just, подумайте

guard c *> e

который также очень хорошо работает с нотацией do. Спасибо Даниэлю Вагнеру за выражение <$.

Обратите также внимание на то, что

fromMaybe x . fmap f

лучше написано

maybe x f
person dfeuer    schedule 26.10.2015
comment
guard не использует пресловутый fail. Раньше он использовал mzero, но после AMP он был обобщен для использования empty Alternative. - person Ørjan Johansen; 26.10.2015
comment
@ØrjanJohansen, ой! Рад это слышать. - person dfeuer; 27.10.2015
comment
Я предпочитаю определять (<?>) :: Alternative f => Bool -> f a -> f a; True <?> x = x; False <?> x = empty, поэтому вместо x <$ guard c мы можем написать c <?> pure x, что мне кажется более информативным. mfilter тоже может пригодиться. - person user3237465; 27.10.2015