重构可能在Yesod中堆叠

时间:2012-11-21 19:53:54

标签: haskell yesod

使用Yesod,我想在每个页面的导航栏中显示用户的个人资料名称,并希望将ProfileId链接到用户的个人资料页面。 config/models包含:

User
    ident Text
    password Text Maybe
    UniqueUser ident
Profile
    username Text
    user UserId
    UniqueProfile user
    UniqueUsername username

来自Foundation.hs的片段:

defaultLayout widget = do
    master <- getYesod
    mmsg <- getMessage
    maid <- maybeAuthId

使用user-id,我可以查询个人资料,但它已在Maybe中被隐藏。 This Stack Overflow question提供了一个很好的提示如何处理所有这些Maybe ...但是,由于我对Haskell的一点经验,我仍然在努力解决它。

我想出了:

mpid <- runMaybeT $ do
    ouid <- MaybeT maybeAuthId
    (Entity pid _) <- MaybeT . runDB . getBy $ UniqueProfile ouid
    return pid

mprofilename <- runMaybeT $ do
    ouid <- MaybeT maybeAuthId
    (Entity _ p) <- MaybeT . runDB . getBy $ UniqueProfile ouid
    return $ profileUsername p

这可行,但不是最佳的 - 重复代码和双重数据库命中。我该如何重构这段代码?

我认为这样可行:

(mpid, mprofilename) <- runMaybeT $ do
    ouid <- MaybeT maybeAuthId
    (Entity pid p) <- MaybeT . runDB . getBy $ UniqueProfile ouid
    return (pid, profileUsername p)

但是,唉,不禁:

Foundation.hs:91:9:
    Couldn't match expected type `Maybe (t0, Text)'
                with actual type `(t1, t2)'
    In the pattern: (mpid, mprofilename)
    In a stmt of a 'do' block:
        (mpid, mprofilename) <- runMaybeT
            $ do { ouid <- MaybeT maybeAuthId;
                (Entity pid p) <- MaybeT . runDB . getBy $ UniqueProfile ouid;
                return (pid, profileUsername p) }
    In the expression:
        do { master <- getYesod;
             mmsg <- getMessage;
             maid <- maybeAuthId;
             (mpid, mprofilename) <- runMaybeT
                 $ do { ouid <- MaybeT maybeAuthId;
                 (Entity pid p) <- MaybeT . runDB . getBy
                     $ UniqueProfile ouid;
                                          .... };
           .... }

我理解错误,但我没有解决。

启发我!

1 个答案:

答案 0 :(得分:3)

您尝试将结果绑定为(Maybe a, Maybe b),但它实际上是Maybe (a, b)

你可以轻松转换它:

unpairMaybe :: Maybe (a, b) -> (Maybe a, Maybe b)
unpairMaybe (Just (x, y)) = (Just x,  Just y)
unpairMaybe Nothing       = (Nothing, Nothing)

然后这应该有效:

(mpid, mprofilename) <- liftM unpairMaybe $ runMaybeT $ do
                ouid <- MaybeT maybeAuthId
                (Entity pid p) <- MaybeT . runDB . getBy $ UniqueProfile ouid
                return (pid, profileUsername p)