如何为不是转换器的monad定义MonadBaseControl?

时间:2019-07-03 10:50:51

标签: haskell monad-transformers

MonadTransControl instance for a custom monad有关,不幸的是(但可以理解),作者放弃了monad-control。但是,这不是我的选择,因为我需要在自定义monad中使用Control.Concurrent.Async.Lifted

{-# LANGUAGE DataKinds, GADTs, ScopedTypeVariables #-}

data FeatureFlag = Feature1 | Feature2

newtype AppM (features :: [FeatureFlag]) a = AppM (ReaderT Env IO a) 
  deriving (Functor, Applicative, Monad, MonadReader Env, MonadIO, MonadThrow, MonadCatch, MonadMask, MonadUnliftIO)

我尝试阅读https://www.stackage.org/haddock/lts-12.1/monad-control-1.0.2.3/Control-Monad-Trans-Control.html,但对我来说似乎没有任何意义。 从概念上我理解为什么MonadBaseControl和朋友是必需的,这要归功于https://www.yesodweb.com/book/monad-control,但我不知道如何实现 >

官方文档的顶部有一个实施指南,但假设使用monad-transformers:

  

在T的构造函数和反构造函数上使用defaultLiftWith和defaultRestoreT函数为所有转换器T定义实例MonadTransControl T。

     

[...]

     

为所有转换器定义实例MonadBaseControl B m => MonadBaseControl B(T m):

我如何为MonadBaseControl IO (AppM fs)编写一个明智的实例,其中在将Monad重新包装并再次包裹时保留fs部分?另外,我假设我不必真正实现MonadTransControl,因为AppM fs不是转换器。

PS:也相关-Is it safe to derive MonadThrow, MonadCatch, MonadBaseControl, MonadUnliftIO, etc?

1 个答案:

答案 0 :(得分:1)

您的AppM基本上是ReaderT的变压器;您只是将其专门用于IO。您可以将其重写为:

newtype AppT (features :: [FeatureFlag]) m a = AppT (ReaderT Env m a)

具有IO版本的类型别名:

type AppM features = AppT features IO

然后,您应该能够使用常规派生子句和独立派生子句的组合来获取所需的类。

至少,以下类型检查和GHC似乎认为它产生了instance MonadBaseControl IO (AppT features IO)

{-# LANGUAGE DataKinds, FlexibleInstances, GADTs, GeneralizedNewtypeDeriving,
    KindSignatures, MultiParamTypeClasses, ScopedTypeVariables, StandaloneDeriving,
    UndecidableInstances #-}

import Control.Monad.Base
import Control.Monad.Catch
import Control.Monad.Reader
import Control.Monad.IO.Unlift
import Control.Monad.Trans.Control

data FeatureFlag = Feature1 | Feature2

data Env

newtype AppT (features :: [FeatureFlag]) m a = AppT (ReaderT Env m a)
  deriving (Functor, Applicative, Monad, MonadReader Env, MonadIO,
            MonadThrow, MonadCatch, MonadMask,
            MonadTrans, MonadTransControl)
type AppM features = AppT features IO
deriving instance MonadBase IO (AppM features)
deriving instance MonadBaseControl IO (AppM features)
deriving instance MonadUnliftIO (AppM features)