1

使用 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

使用用户 ID,我可以查询配置文件,但它被埋在Maybes 中。 这个 Stack Overflow 问题很好地提示了如何处理所有这些问题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;
                                          .... };
           .... }

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

开导我!

4

1 回答 1

3

您正在尝试将结果绑定为 a (Maybe a, Maybe b),但它实际上是 a 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)
于 2012-11-21T20:04:54.523 回答