Monad 转换器的用途和示例?

Bab*_*ham 5 monads haskell

我正在讨论 Monad Transformers,我知道它们的主要作用是提供一个 Monadic 容器来保存不同类型的 monad,它提供了一个通用接口,可以在计算中操作“嵌套”monad。

我尝试实现我自己的变压器:

data CustomTransformer a = CustomTransformer

class TransformerClass m a where
  lift :: m a -> CustomTransformer (m a)

instance TransformerClass Maybe a where
 lift (Just a) = CustomerTransformer (Just a)
Run Code Online (Sandbox Code Playgroud)

读完这篇论文,我明白这是不正确的。他们的例子表明:

class MonadTrans r where
  lift :: Monad m => m a -> (r m) a
Run Code Online (Sandbox Code Playgroud)

这将动作嵌套a在 monad 转换器中r m

我不明白使用单子变压器如何帮助处理计算中的多个单子类型?谁能提供一个简单的解释和例子?

Ben*_*son 5

我发现了解这里起作用的类型很有帮助。

首先,如您所知,monad是一个与两个操作配对的类型构造函数 m :: * -> *return :: a -> m a(>>=) :: m a -> (a -> m b) -> m b

class Monad (m :: * -> *) where
    return :: a -> m a
    (>>=) :: m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)

monad 转换器的想法是,它们是一种将一个 monad 转换为另一个 monad 的类型级函数。因此,考虑到 monad 是单参数类型构造函数* -> *,monad 转换器必须是 kind 的类型(* -> *) -> (* -> *),或者(* -> *) -> * -> *一旦删除括号。monad 转换器是双参数 类型,其第一个参数是 monad,第二个参数是值。

更具体地说, monad 转换器是一种 type t :: (* -> *) -> * -> *,因此每当m是 monad时t m也是一个 monad。我们还要求t m是一个比更大的单子m,因为 中的任何动作都m可以嵌入到 中t m

class MonadTrans t where
    transform :: Monad m :- Monad (t m)
    lift :: Monad m => m a -> t m a
Run Code Online (Sandbox Code Playgroud)

我在;的定义中使用了Kmett中的“蕴含”运算符。:-是一个证明,证明是 a意味着是 a 。(in的版本省略了成员,因为编写它时 GHC 不支持运算符。)constraintstransformtransformmMonadt mMonadMonadTranstransformerstransform:-

重要的是,t m a(aka (t m) a) 的含义与 不同t (m a)。前者是t应用于m和 的二参数类型a。后者是一种t应用于 的单参数类型m a

一个非常简单的例子——因为我在手机上——monad 转换器的定义如下:

newtype IdentityT m a = IdentityT { runIdentityT :: m a }

instance Monad m => Monad (IdentityT m) where
    return = IdentityT . return
    IdentityT m >>= f = IdentityT $ m >>= (runIdentityT . f)

instance MonadTrans IdentityT where
    transform = Sub Dict
    lift = IdentityT
Run Code Online (Sandbox Code Playgroud)

请注意,这IdentityT是一个双参数数据类型;第一个参数m :: * -> *是 monad,第二个参数a :: *是常规类型。

ghci> :k IdentityT
IdentityT :: (* -> *) -> * -> *
Run Code Online (Sandbox Code Playgroud)