在Snap中避免链式查找的案例表达式

时间:2014-04-23 12:32:23

标签: haskell monads haskell-snap-framework

我正在玩Snap框架并经常遇到 我根据我得到的参数进行数据库查找的情况 来自表格领域。

考虑例如以下两个功能

getParam :: (MonadSnap m) => ByteString -> m (Maybe ByteString)
doLookup :: (MonadIO (m b v), MonadSnaplet m, MonadState s (m b b), HasAcid s UrlDB) => ByteString -> m b v (EventResult QueryByURL)

其中UrlDB是整数和URL之间的映射。第二种复杂的类型签名 功能是由于使用酸态并最终导致Maybe Integer

queryByURL :: Text -> Query UrlDB (Maybe Integer)

到目前为止,我的处理程序看起来像

indexHandler :: Handler MyApp MyApp ()
indexHandler = do
    mUrl <- getParam "url"
    case mUrl of
        Nothing  -> render "index"
        Just url -> do
            mId <- doLookup $ url
            case mId of
                Nothing -> render "index"
                Just i  -> do
                               fancyStuffWith i
                               render "index"

现在,让我烦恼的第一件事就是案例表达的楼梯。 第二件事是render "index"的三倍出现。 基本上,每当两个Maybe值中的一个为Nothing时,我想返回 默认视图。

最干净的方法是什么?

2 个答案:

答案 0 :(得分:5)

这就是MaybeT monad变换器的用途。你的代码可以这样写。

indexHandler :: Handler MyApp MyApp ()
indexHandler = do
    runMaybeT $ do
        url <- MaybeT $ getParam "url"
        i <- MaybeT $ doLookup url
        fancyStuffWith i
    render "index"

errors package汇集了这些东西并添加了许多便利功能来处理它们。除了MaybeT之外,EitherT monad变换器也可以执行类似的操作,但会跟踪错误消息,以便您可以跟踪计算失败的时间。

答案 1 :(得分:2)

为了避免重复渲染“index”,你必须看到你基本上在所有代码路径的末尾调用它。然后,您可以尝试使用函数抽象该模式匹配部分。结果并不完美,但略胜一筹。

indexHandler :: Handler MyApp MyApp ()
indexHandler = do
    withJust $ getParam "url" $ \url ->
        withJust $ doLookup url $ fancyStuffWith
    render "index"
  where
    withJust :: (IO (Maybe a)) -> (a -> IO()) -> IO ()
    withJust iomval cmd = do
        mval <- iomval
        case mval of
            Nothing -> return ()
            Just val -> cmd val

withJust函数执行的IO操作可能无法带来值。如果成功,则将值传递给另一个命令。