我正在尝试制作一个阅读器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)’
失败,模块加载:无。
答案 0 :(得分:2)
正确的实施是:
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 -> r -> a
传递给r -> a
只是ghci> :t runReader
runReader :: Reader r a -> r -> a
)。
要了解正在发生的事情,可能有助于检查runReader的类型:
r
此函数将读者的第一个参数作为其第二个参数a
,并返回\r -> runReader (f $ m r) r
。因此我们可以看到子表达式
r -> a
具有类型Reader
,是传递给r
构造函数的好选择。如果你遗漏了最后runReader
,你只将r -> a
应用于一个参数,结果你得到了curry \r -> runReader (f $ m r)
函数,那么:
r -> r2 -> a
的类型为Reader r (r2 -> a)
,当您将其提供给阅读器时,您将获得>>=
,{{1}}的类型不正确。