1

我正在重构一些旧代码,这些代码位于多态但类型类受限的 monad 中:

class ( MonadIO m
      , MonadLogger m
      , MonadLoggerIO m
      , MonadThrow m
      , MonadCatch m
      , MonadMask m
      , MonadBaseControl IO m
      , MonadUnliftIO) => HasLogging m where

在旧代码中,应用程序的主要单子是......

type AppM = ReaderT Env IO

...现在将更改为...

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

在这种情况下,自动推导出以下内容是否安全:

  • 单子投掷
  • MonadCatch
  • MonadMask
  • MonadBaseControl
  • MonadUliftIO

在不深入 GHC 内部的情况下,当编译器自动派生事物时,开发直觉的最佳方式是什么?

4

1 回答 1

1

用户手册有关于每个扩展的文档,并且它不断变得更好;这是关于派生的部分,应该足以了解实际发生的情况:https ://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#extensions-to-the-deriving-mechanism

在这种情况下,所有这些类都由GeneralizedNewtypeDeriving.

{-# LANGUAGE GeneralizedNewtypeDeriving, UndecidableInstances #-}

module M where

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

newtype Foo a = Foo (ReaderT () IO a)
  deriving (Functor, Applicative, Monad, MonadIO, MonadUnliftIO, MonadThrow, MonadCatch, MonadMask, MonadBase IO, MonadBaseControl IO)

通常,用户定义类的三个相关扩展是GeneralizedNewtypeDerivingDerivingViaDeriveAnyType。并且还值得DerivingStrategies明确指出正在使用的内容。

于 2019-07-03T10:59:41.017 回答