haskell提升操作

Monad在haskell中是非常常见的操作,一个函数要在不同的Monad中工作就离不开lift。

lift

来自 MonadTrans 类,当使用 Monad Transformer(如 StateT, ReaderT, MaybeT 等)时,操作底层 Monad(例如 IO)需要用 lift。

1
lift :: Monad m => m a -> t m a
1
2
3
4
5
6
7
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.State

example :: StateT Int IO ()
example = do
lift $ putStrLn "This is lifted from IO"
modify (+1)

liftM

是 fmap 的一个特化,用于 Monad,而不是 Functor。将一个二元函数提升为Monad操作

1
liftM :: Monad m => (a -> b) -> m a -> m b
1
2
3
4
import Control.Monad (liftM)

example :: IO Int
example = liftM (+1) (return 41) -- 结果是 IO 42

(+1)操作本来接收一个Int,提升后可以接收一个IO Int

在 GHC 7.10 后,Applicative 成为了 Monad 的超类,因此可以直接用 fmap,推荐用 fmap 或 <$> 而不是 liftM。

1
2
3
4
import Control.Monad (liftM)

example :: IO Int
example = (+1) <$> (return 41) -- 结果是 IO 42

liftA

liftA 针对的是 Applicative,而 liftM 针对的是 Monad。由于 Monad 是 Applicative 的子类,现在两者的功能重叠,通常用 <$>。

liftIO

用于将 IO 操作提升到任何支持 MonadIO 的 Monad 中

1
liftIO :: MonadIO m => IO a -> m a
1
2
3
4
5
6
import Control.Monad.IO.Class (liftIO)

example :: StateT Int IO ()
example = do
liftIO $ putStrLn "This is an IO action"
modify (+1)

liftHandler

yesod框架用于提升handler到另一个Monad中

1
2
3
4
5
6
7
8
9
10
11
12
13
class (MonadResource m, MonadLogger m) => MonadHandler m where
type HandlerSite m
type SubHandlerSite m
liftHandler :: HandlerFor (HandlerSite m) a -> m a
liftSubHandler :: SubHandlerFor (SubHandlerSite m) (HandlerSite m) a -> m a

instance MonadHandler (HandlerFor site) where
type HandlerSite (HandlerFor site) = site
type SubHandlerSite (HandlerFor site) = site
liftHandler = id
{-# INLINE liftHandler #-}
liftSubHandler (SubHandlerFor f) = HandlerFor f
{-# INLINE liftSubHandler #-}