【问题标题】:How to define MonadBaseControl for a monad that is NOT a transformer?如何为不是变压器的 monad 定义 MonadBaseControl?
【发布时间】:2019-07-03 10:50:51
【问题描述】:

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 定义实例 MonadTransControl T,在 T 的构造函数和解构函数上使用 defaultLiftWith 和 defaultRestoreT 函数。

[...]

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

如何为 MonadBaseControl IO (AppM fs) 编写一个合理的实例,其中 fs 部分在 monad 被解包并再次包装时被保留?另外,我假设我不是真的必须实现MonadTransControl,因为AppM fs 不是转换器。

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

【问题讨论】:

  • 如果你只是货物崇拜 ReaderT 的实例会出现什么问题?

标签: haskell monad-transformers


【解决方案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)

【讨论】:

  • 所以在我看来,unlift 实例使用功能标记其状态可能会很好,以防止人们通过 unlifting 写入AppT fs m a -> AppT fs' m a。也许这就是最初的提问者所追求的?
猜你喜欢
  • 2021-09-21
  • 2018-04-18
  • 1970-01-01
  • 1970-01-01
  • 2021-03-18
  • 2014-11-30
  • 1970-01-01
  • 1970-01-01
  • 2014-11-06
相关资源
最近更新 更多