我正在尝试设置授权方案,其中我检查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' -> ...
答案 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]
在这种特殊情况下,如果列表中至少有一个sequence
,Nothing
将返回Nothing
,但如果它们都是Just
s,那么将它们全部加入一个Just
。
剩下的就是将sequence
映射到外部Maybe
:
fmap sequence :: Maybe [Maybe r] -> Maybe (Maybe [r])
现在这正是我们加入所需的形式:
join . fmap sequence :: Maybe [Maybe r] -> Maybe [r]
因此,直观地说,上述函数的作用是,如果所有内部Maybe
都是Just
并且外部Maybe
是Just
,那么它会融合将整个结果整合到包含列表的单个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制定它。