我只是设法了解了MonadReader类的定义

class Monad m => MonadReader r m | m -> r where
...

在阅读Haskell中的功能依赖文档之后,现在我可以理解| m -> r指定类型变量rm唯一地确定。基于到目前为止我所见过的MonadReader的一些典型实例,我认为这一要求是合理的(例如Reader),但是在我看来,即使没有此功能依赖项,我们仍然可以定义类似Reader的实例。

我的问题是,为什么在MonadReader的定义中需要功能依赖?从某种意义上说,在没有MonadReader不能正确定义MonadReader的情况下,这是否是功能上必要的?或者仅是限制MonadReader使用方式的限制,以便MonadReader的实例都能以某种预期的方式运行?

最佳答案

需要以对用户更方便的方式来进行类型推断。

例如,没有fundep,它将无法编译:

action :: ReaderT Int IO ()
action = do
  x <- ask
  liftIO $ print x

为了进行以上编译,我们需要编写
action :: ReadertT Int IO ()
action = do
  x <- ask :: ReadertT Int IO Int
  liftIO $ print x

这是因为,在没有资助者的情况下,编译器无法推断xInt。毕竟monad ReadertT Int IO可能有多个实例
instance MonadReader Int (ReaderT Int IO) where
   ask = ReaderT (\i -> return i)
instance MonadReader Bool (ReaderT Int IO) where
   ask = ReaderT (\i -> return (i != 0))
instance MonadReader String (ReaderT Int IO) where
   ask = ReaderT (\i -> return (show i))
-- etc.

因此,程序员必须提供一些强制使用x :: Int的注释,否则代码将变得模棱两可。

10-08 12:36