Как определить MonadBaseControl для монады, которая НЕ является преобразователем? - PullRequest
1 голос
/ 03 июля 2019

Относится к Экземпляр MonadTransControl для пользовательской монады , где, к сожалению (но вполне понятно), автор отказался от monad-control.Однако, это не вариант для меня, потому что мне нужно использовать 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, но я не могу понять, как реализовать это.

Официальные документы имеют руководство по реализации в самом верху, но оно предполагает монадные преобразователи:

Определите экземпляры MonadTransControl T для всех преобразователей T, используя функции defaultLiftWith и defaultRestoreT дляконструктор и деконструктор T.

[...]

Определение экземпляров MonadBaseControl B m => MonadBaseControl B (T m) для всех преобразователей:

Как написать разумный экземпляр для MonadBaseControl IO (AppM fs), где часть fs сохраняется, когда монада развернута и снова обернута? Кроме того, я предполагаю, что мне не нужно реализовывать MonadTransControl, поскольку AppM fs не является преобразователем.

PS: также связано - Безопасно ли получать MonadThrow, MonadCatch, MonadBaseControl, MonadUnliftIO и т. Д.?

1 Ответ

1 голос
/ 04 июля 2019

Ваш 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...