为新类型创建 MonadBaseControl 实例

creating MonadBaseControl instance for newtype

假设我有简单的新类型声明

newtype Foo a = Foo { unFoo :: ReaderT Int IO a }

我想创建 MonadBaseControl IO 的 Foo 实例。这应该很容易,因为 ReaderT Int IO 已经是 MonadBaseControl IO 的一个实例。但是,使用 GeneralizedNewtypeDeriving 自动派生它不起作用,因为 MonadBaseControl class 具有关联类型。

如何为 Foo 编写 MonadBaseControl IO 实例? defaultLiftBaseWith 和 defaultRestoreM 应该会有帮助,但要破译它们的类型有点困难。

Foo 既不是 "base" monad,也不是 monad 转换器。 defaultLiftBaseWith 在这里没有用,因为您希望 Foo 的实例与 ReaderT Int IO 的实例相同。

首先,使用GND获取无聊的实例:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import Control.Monad.Trans.Control
import Control.Monad.Base 
import Control.Monad.Reader 
import Control.Applicative

newtype Foo a = Foo { unFoo :: ReaderT Int IO a } 
  deriving (Monad, Applicative, Functor, MonadBase IO)

MonadBaseControl IO 的实例只是删除新类型,使用 ReaderT 实例中的函数,并将结果放回新类型:

instance MonadBaseControl IO Foo where
  type StM Foo a = a 
  liftBaseWith f = Foo $ liftBaseWith $ \q -> f (q . unFoo)
  restoreM = Foo . restoreM 

请注意,如果 StM 不是 关联类型族,您可以执行类似

newtype Foo a = Foo { unFoo :: ReaderT Int IO a } 
  deriving (Monad, Applicative, Functor, MonadBase IO, MonadBaseControl IO)

type instance StM Foo a = a