getUser :: Handler (MaybeUser) getUser = do mToken <- lookupBearerAuth case mToken of Nothing -> return Nothing Just token -> do mUserJson <- getFromRedis token case mUserJson of Nothing -> return Nothing Just userJson -> decodeUser userJson
-- 为MyContainer实现Monad方法,定义>>=的逻辑 instanceMonadMyContainerwhere (>>=) :: MyContainer a -> (a -> MyContainer b) -> MyContainer b -- bind 操作符 MyContainer a >>= f = -- 额外的操作 doSomeThing -- 将转换函数应用于a f a
-- 使用MyContainer test :: MyContainerString test = MyContainer"A" >>= appendB
-- test2是test1的do写法 test2 :: MyContainerString test2 = do a <- MyContainer"A" -- 执行了doSomething隐式操作 appendB a
知道了Monad可以实现隐式操作之后,我们就可以将Nothing的判断放到Monad的隐式操作中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
dataMaybeT a = MaybeT { maybeTValue :: Maybe a } instanceMonad m => MonadMaybeTwhere return = MaybeT . Just
-- 根据Monad的签名,可以推导出x和f的定义 -- x: MaybeT a -- f: a -> MaybeT b x >>= f = let v = maybeTValue x incase v of -- 若value是nothing不处理 Nothing -> return Nothing Just y -> (f y)
主题:MaybeT
下面是mtl包下的MaybeT的Monad实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
newtypeMaybeT m a = MaybeT { runMaybeT :: m (Maybea) }
-- (MaybeT m)的monad实现 instanceMonad m => Monad (MaybeTm) where return = MaybeT . return . Just
-- 根据Monad的签名,可以推导出x和f的定义 -- x: MaybeT m a -- f: a -> MaybeT m b (>>=) x f = MaybeT $ do v <- runMaybeT x case v of Nothing -> return Nothing Just y -> runMaybeT (f y)
对比上面的设计,这种设计增加了一个Monad参数m。这么做的原因是因为MaybeT 的主要目的是作为 Monad Transformer,使 Maybe Monad 能够与其他 Monad(如 IO、List 等)堆叠。通过定义为 MaybeT m a = m (Maybe a),它可以包裹任何 Monad 上下文 m,使其兼容多种 Monad,而不是仅限于单一的 Maybe 值。