ReaderT的派生

3
我正在使用ReaderT编写此类型的Monad实例,并通过派生实现。
newtype HIO a = HIO {runHIO :: Set HiPermission -> IO a}

我已经尝试过用这种方式实现

newtype HIO a = HIO {runHIO :: Set HiPermission -> IO a}
  deriving (Functor, Applicative, Monad) via (ReaderT (Set HiPermission) IO) 

但是出现了错误:

Couldn't match representation of type `Set HiPermission -> IO c' with that of `ReaderT (Set HiPermission) IO c' 
arising from the coercion of the method

我做错了什么?


4
ReaderT 既是类型构造器,也是值构造器。为了让 DerivingVia 生效,新类型构造器必须在作用域内,而不仅仅是类型本身。也就是说,你需要像 import Control.Monad.Reader 或者 import Control.Monad.Reader ( ReaderT(..) ) 或者 import Control.Monad.Reader ( ReaderT(ReaderT) ) 这样引入。但是 import Control.Monad.Reader ( ReaderT ) 不管用,因为它只引入了类型而没有引入构造器。 - danidiaz
ghci 命令 :instances ReaderT (Set HiPermission) IO 列出可派生的实例,多参数类型目前不在列表中,因此它不会列出 MonadReader (Set HiPermission),即使它可以被派生。 - Iceland_jack
1
@danidiaz 我认为你应该将它变成一个答案。@MariaZ 假设导入 ReaderT 值构造器会解决你的问题? - leftaroundabout
1个回答

2
问题的可能原因是您导入了ReaderT类型,但未导入ReaderT 值构造函数,即类型为(r -> m a) -> ReaderT r m a的函数,该函数构建类型为ReaderT的值。
例如,您可能已经编写了:
import Control.Monad.Reader ( ReaderT ) -- only the ReaderT type

替代

import Control.Monad.Reader -- import everything

或者

import Control.Monad.Reader ( ReaderT(..) ) -- import the type and its constuctor

但是,为什么ReaderT值构造函数需要在范围内呢?

原因在于DerivingVia依赖于Data.Coerce。在定义实例的模块中,我们必须能够强制转换到“via”类型,即ReaderT (Set HiPermission) IO

而且,事实证明,要使用强制转换来包装/解包像ReaderT这样的新类型,我们需要在范围内拥有它的值构造函数。引用自coerce Haddocks

The third kind of instance exists for every newtype NT = MkNT T and comes in two variants, namely

instance Coercible a T => Coercible a NT

instance Coercible T b => Coercible NT b

This instance is only usable if the constructor MkNT is in scope.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接