【问题标题】:Reader monad core operator not working阅读器 monad 核心运算符不工作
【发布时间】:2014-12-10 20:33:19
【问题描述】:

我正在尝试制作 Reader monad,但它不起作用(加载),我做错了什么?谢谢

newtype Reader r a = Reader { runReader :: r -> a }

instance Monad (Reader r) where
    return a = Reader $ \r -> a

    Reader m >>= f = Reader $ \r ->
        let a = m r
        in runReader (f a)

我收到此错误:

Couldn't match type ‘b’ with ‘r -> b’
  ‘b’ is a rigid type variable bound by
      the type signature for
        (>>=) :: Reader r a -> (a -> Reader r b) -> Reader r b
      at Reader.hs:24:14
Expected type: Reader r b
  Actual type: Reader r (r -> b)
Relevant bindings include
  f :: a -> Reader r b (bound at Reader.hs:24:18)
  m :: r -> a (bound at Reader.hs:24:12)
  (>>=) :: Reader r a -> (a -> Reader r b) -> Reader r b
    (bound at Reader.hs:24:5)
In the expression: Reader $ \ r -> let a = ... in runReader (f a)
In an equation for ‘>>=’:
    (Reader m) >>= f = Reader $ \ r -> let ... in runReader (f a)
In the instance declaration for ‘Monad (Reader r)’

失败,已加载模块:无。

【问题讨论】:

  • 请看后面的编辑
  • 我认为您在进行模式匹配时可能需要括号(Reader m)
  • 正确答案是 (runReader (f a)) r 我之前在评论中看到过,我只是想知道它是否正确,为什么会这样。给谁先贴:把它作为答案。我也收到此警告“Reader”是 Monad 的一个实例,但不是 Applicative - 根据 Applicative-Monad 提案,这将成为 GHC 7.10 中的错误。
  • @genisage 您可以解释这是正确的,因为您为mf (m r) 的结果提供了相同的r,这正是阅读器monad 的设计目的。您希望它对所有内容都使用完全相同的r,而>>= 的这个定义意味着必须保持。
  • @CosminMihai 关于不是 Applicative 实例的警告对于玩弄并不是太重要,但是如果您要将自定义阅读器 monad 变成在 hackage 上分享的东西,您需要确保应用实例存在。这也意味着您需要一个仿函数实例,但经过一番谷歌搜索后,这两个实例都非常简单。

标签: haskell


【解决方案1】:

正确的实现是:

newtype Reader r a = Reader { runReader :: r -> a }

instance Monad (Reader r) where
    return a = Reader $ \_ -> a
    Reader m >>= f = Reader $ \r -> runReader (f $ m r) r

您缺少的额外混乱是绑定中的最后一个r。由于此参数不存在,因此它声称您在构建 Reader 时将r -> a 误认为a(换句话说,当它只需要r -> a 时,您已将r -> r -> a 交给它) .

要查看发生了什么,检查 runReader 的类型可能会有所帮助:

ghci> :t runReader
runReader :: Reader r a -> r -> a

此函数将读取器作为其第一个参数,将r 作为其第二个参数,并返回一个a。因此我们可以看到子表达式

\r -> runReader (f $ m r) r

具有r -> a 类型,并且是移交给Reader 构造函数的良好候选者。如果你去掉最后一个r,你只对一个参数应用了runReader,结果你得到了咖喱r -> a函数,所以:

\r -> runReader (f $ m r)

具有r -> r2 -> a 类型,当您将其提供给阅读器时,您将获得Reader r (r2 -> a),它没有>>= 的正确类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-01
    • 1970-01-01
    • 2018-06-16
    • 1970-01-01
    • 2015-01-12
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    相关资源
    最近更新 更多