2

我目前正在尝试重载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是由于MonadTransMonadReader限制。基本上,这迫使所有关联的类型实例都是单态类型(对吗?)。

然后我想重新设计它,Result简单地制作一个多态变量:

...
class FooReader prefix m where
  runFooReader :: forall b result. m b -> prefix -> result b

...但是在实例中,类型resultand w(例如,如果是ReaderT prefix was m将不会统一。有没有办法让这个resultvarialbe / idea 多态,但可以确定?

4

1 回答 1

4

清理语法错误并添加一个 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
于 2014-12-22T06:44:59.143 回答