深可能与yesod堆叠

时间:2012-08-26 14:01:53

标签: haskell yesod

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

编辑:

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

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

3 个答案:

答案 0 :(得分:6)

您可以将MaybeT完全用于Yesod。就这样做:

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)

答案 1 :(得分:2)

根据我的理解,你的图层看起来像:

Maybe [Maybe r]

...并且您希望将join两个Maybe放在一起,但列表仍然存在。这正是sequence解决的问题:

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

请注意,如果我们将sequence专门化为Maybe monad,我们会得到:

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

在这种特殊情况下,如果列表中至少有一个sequenceNothing将返回Nothing,但如果它们都是Just s,那么将它们全部加入一个Just

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

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

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

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

因此,直观地说,上述函数的作用是,如果所有内部Maybe都是Just并且外部MaybeJust,那么它会融合将整个结果整合到包含列表的单个Just中。但是,如果任何Maybe(内部或外部)都是Nothing,则最终结果为Nothing

请注意,尽管做了一堆盲目类型追逐,我们最终得到了一个直观地做正确事情的功能。这是以类别理论为基础的抽象的力量。

答案 2 :(得分:1)

“处理深度maybes”的含义并不完全清楚,但您可以使用monadic join(来自Control.Monad)一次删除一级嵌套。

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

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