Haskell中的变量关联类型/数据类型

时间:2014-12-22 05:48:28

标签: haskell polymorphism monad-transformers associated-types

我目前正在尝试重载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

...但在实例中,类型resultw(例如ReaderT prefix wm,例如)不会统一。有没有办法让这个result varialbe / idea多态,但可以判断?

1 个答案:

答案 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