Haskell 读卡器monad核心运算符不工作
我试图制作一个阅读器monad,但它不工作(加载),我做错了什么?谢谢Haskell 读卡器monad核心运算符不工作,haskell,Haskell,我试图制作一个阅读器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
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)’
失败,已加载模块:无。正确的实现是:
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
。由于此参数不存在,因此它声称在构建读卡器时,您将r->a
误认为a
(换句话说,当它只需要r->a
时,您将r->r->a
交给了它)
要查看发生了什么,检查runReader的类型可能会有所帮助:
ghci> :t runReader
runReader :: Reader r a -> r -> a
此函数将读取器作为其第一个参数,将读取器作为其第二个参数,并返回一个a
。因此,我们可以看到子表达式
\r -> runReader (f $ m r) r
具有类型r->a
,是将其交给读取器
构造函数的好人选。如果您取消最后一个r
,您只对一个参数应用了runReader
,结果得到了当前的r->a
函数,因此:
\r -> runReader (f $ m r)
具有类型
r->r2->a
,当您将其提供给读卡器时,您将获得读卡器r(r2->a)
,但它的类型不适合>=
请参阅后面的编辑我想在进行模式匹配时可能需要括号(Reader m)
。正确答案是(runReader(f a))r我在前面的评论中看到过,我只是想知道它是否正确,为什么是这样。给谁先贴的:把它作为答案。我还收到了这样一条警告:“Reader”是Monad的一个实例,但不适用于应用程序-这将成为GHC 7.10中的一个错误,根据应用程序Monad的建议。@genisage您可以解释这是正确的,因为您为m
和f(mr)
的结果提供了相同的r
,这正是读卡器monad的设计目的。您希望它对所有内容都使用完全相同的r
,而>=
的这个定义意味着它必须保持不变。@CosminMihai关于不作为Applicationve实例的警告对于玩游戏来说并不太重要,但是如果您想让您的自定义阅读器monad成为hackage上共享的东西,您需要确保应用程序实例存在。这也意味着您将需要一个函子实例,但这两个实例在谷歌搜索后都非常简单。