清理语法错误并添加一个 kind 注释Result
,我们得到:
class ( Monad Result
, MonadTrans m
, MonadReader prefix m
) => FooReader prefix m where
type Result :: * -> *
runFooReader :: forall b. m b -> prefix -> Result b
instance Monad m => FooReader prefix (ReaderT prefix m) where
type Result = m -- Again, error triggered here
runFooReader = runReaderT
还有一个更有趣的错误:
The RHS of an associated type declaration mentions type variable `m'
All such variables must be bound on the LHS
这在GHC 文档中进行了扩展:
关联族实例右侧的类参数的可见性仅取决于族的参数。例如,考虑简单的类声明
class C a b where
data T a
两个类参数中只有一个是数据族的参数。因此,以下实例声明无效:
instance C [c] d where
data T [c] = MkT (c, d) -- WRONG!! 'd' is not in scope
在这里,数据实例的右侧提到了在其左侧没有出现的类型变量 d。我们不能承认这样的数据实例,因为它们会危及类型安全。
为了探索“它会损害类型安全”这一点,想象一下这个 GHCi 会话:
> :kind! Result
Result :: * -> *
= {- ... well, what? m? -}
你可能的意思是type Result prefix (ReaderT prefix m) = m
。
仍然存在错误。值得注意的是,类型m
不一致;MonadTrans
需要一个参数,(* -> *) -> * -> *
而MonadReader
第二个参数需要* -> *
。我不明白你为什么需要MonadTrans
.
我不明白您所说的“强制所有关联类型实例为单态类型”是什么意思;你写的Result
类型不是真正的类型函数,因为它没有任何参数;它的 LHS 上没有任何类型变量。
这是编译的东西:
class ( Monad (Result m)
, MonadReader prefix m
) => FooReader prefix (m :: * -> *) where
type Result m :: * -> *
runFooReader :: forall b. m b -> prefix -> Result m b
instance Monad m => FooReader prefix (ReaderT prefix m) where
type Result (ReaderT prefix m) = m
runFooReader = runReaderT
> :kind! Result (ReaderT Int IO)
Result (ReaderT Int IO) :: * -> *
= IO