单元的元组(monad,state)?

awl*_*wer 1 io monads haskell state-monad

我正在尝试使用Monads编写一个Haskell"数字猜测"游戏程序,但我被困住了:
我尝试了简单的状态monad:

data SM a = SMN (S -> (a, S))
instance Monad SM where
 SMN c1 >>= fc2 = SMN (\s0 -> let (r, s1) = c1 s0 in
                                let SMN c2 = fc2 r in
                                  c2 s1)
Run Code Online (Sandbox Code Playgroud)

我需要在元组(a,S)的"IO端"执行IO任务,也就是说,我尝试做类似的事情:

SMN c1 >>= fc2 = SMN (\s0 -> let (r, s1) = c1 s0 in
                               let SMN c2 = fc2 r in
                                 let (r1, s2) = c2 s1 in
                                   let r2 = r1 >>= (\_ -> r) in
                                     (r2, s2))
Run Code Online (Sandbox Code Playgroud)

简而言之,我想要定义的绑定运算符与原始状态monad相同,除了我们绑定r1和将参数带入r的常量函数(以便将两个操作链接在一起).但是ghc告诉我a是一个刚性类型变量......这是什么意思?我不能在一个绑定运算符中使用另一个绑定运算符?
如果是这样,那么有没有办法实现这样的绑定运算符?怎么样?
因为我是Haskell的新手(我想我可能有一个关于函数的符号错误

\_ -> r
Run Code Online (Sandbox Code Playgroud)

),提前感谢任何意见和参考.
PS我对数据类型SM和类型构造函数SMN使用了不同的符号,以便区分它们.

Dan*_*ner 7

类型(>>=)是:

Monad m => m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)

由于您正在编写实例SM,因此实例中的绑定类型是

SM a -> (a -> SM b) -> SM b
Run Code Online (Sandbox Code Playgroud)

请注意,两个ab完全不受限制的类型变量.这意味着无论我选择放入哪种类型,您提供的任何实施都必须有效.特别是,我可以选择,比如说,Int两个ab:

SM Int -> (Int -> SM Int) -> SM Int
Run Code Online (Sandbox Code Playgroud)

现在很清楚为什么你的实现不好:它会试图把它Int当作一个monadic动作来对待(>>=)它.

如果你想在你的绑定中做monadic动作,你将不得不以某种方式谈论你的类型中的monad; 例如,一种标准方法是定义

data SMT m a = SMT (S -> m (a, S))
Run Code Online (Sandbox Code Playgroud)

并给出一个像:

instance Monad m => Monad (SMT m) where -- ...
Run Code Online (Sandbox Code Playgroud)

SM如果您愿意,可以使用Identitymonad作为嵌套monad 恢复法线.