6

我正在尝试设置一个授权方案,我在其中检查 1. 用户已登录 2. 用户有权访问某个对象。为此,我首先调用maybeAuthId,然后尝试获取当前对象,并“加入”到另一个列出权限的表。有两个级别的可能案例和一个级别的空列表案例。我曾想过使用 MaybeT,但要么我太累而无法让它工作,要么“不是真正的 monad 转换器”-handler-transformers 不能与 MaybeT 一起使用。有没有很好的方法来处理深度可能?

编辑:

我似乎有点不清楚。我的意思是我有这样的东西:

case foo of
   Nothing -> something
   Just foo' -> do
      bar <- somethingelse
      case bar of
         Nothing -> ...
         Just bar' -> ...
4

3 回答 3

6

您完全可以使用MaybeTYesod。这样做:

runMaybeT $ do
  uid <- MaybeT maybeAuthID
  car <- MaybeT . runDB . getBy $ UniqueCarOwner uid
  location <- MaybeT . liftIO . ciaLocateLicensePlate . licensePlate $ car
  country <- MaybeT . findCountry $ location
  return (car, country)

正如您所说,大多数函数都没有针对 Yesod 中的通用错误处理进行优化。但是,如果你有某种形式的东西Monad m => m (Maybe a),你可以简单地用MaybeT把它从里到外变成Monad m => Maybe (m a).

于 2012-08-26T17:59:39.937 回答
2

据我了解,您的图层如下所示:

Maybe [Maybe r]

...并且您想join将两个Maybes 放在一起,但列表妨碍了。这正是要sequence解决的问题:

sequence :: (Monad m) => [m r] -> m [r]

请注意,如果我们专注sequenceMaybe我们得到的 monad:

sequence :: [Maybe r] -> Maybe [r]

在这种特殊情况下,如果列表中至少有一个,sequence将返回 a ,但如果它们都是s,那么它将把它们全部连接成一个 s 。NothingNothingJustJust

剩下的就是映射sequence到外部Maybe

fmap sequence :: Maybe [Maybe r] -> Maybe (Maybe [r])

现在这正是我们需要加入的形式:

join . fmap sequence :: Maybe [Maybe r] -> Maybe [r]

因此,直观地说,上述函数所做的是,如果所有内部Maybes 都是Justs 而外部Maybe是 a Just,那么它将整个结果融合到一个Just包含列表的单个中。但是,如果任何Maybe(内部或外部)是 a Nothing,则最终结果是 a Nothing

请注意,尽管做了一堆盲目的类型追逐,我们最终还是得到了一个直观地做正确事情的函数。这就是基于范畴论的抽象的力量。

于 2012-08-26T19:13:12.753 回答
1

目前尚不清楚“处理深度可能”是什么意思,但您可以使用 monadic join(from Control.Monad) 一次删除一层嵌套。

ghci> :m +Control.Monad
ghci> join (Just (Just 3))
Just 3
ghci> join (Just Nothing)
Nothing
ghci> join Nothing
Nothing

不过,使用 MaybeT 可能更适合您的问题。如果你澄清你想要做什么,我们可以帮助你用 MaybeT 制定它。

于 2012-08-26T15:11:30.257 回答