我目前正在尝试重载MonadTrans
以前的提取功能。我目前的尝试是将内部单子m
作为关联类型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)
type Result = m -- This is there the error is thrown
runFooReader = runReaderT
Foo
形成有趣的唯一原因是MonadTrans
和MonadReader
限制。基本上,这是强制所有关联的类型实例是单态类型(正确吗?)。
然后我想重新设计它,使Result
只是一个多态的可变:
...
class FooReader prefix m where
runFooReader :: forall b result. m b -> prefix -> result b
...但在实例中,类型result
和w
(例如ReaderT prefix w
为m
,例如)不会统一。有没有办法让这个result
varialbe / idea多态,但可以判断?
答案 0 :(得分:4)
清理语法错误并向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
这在the GHC docs:
中展开右侧的类参数的可见性 相关的族实例仅取决于的参数 家庭。例如,考虑简单的类声明
class C a b where data T a
两个类参数中只有一个是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