元组的单子(单子,状态)?
A monad of tuples (monad, state)?
我正在尝试使用 Monad 编写 Haskell "number-guessing" 游戏程序,但我被卡住了:
我尝试了简单的状态 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)
而且我需要在元组 (a, S) 的 "IO-side" 上执行 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))
简而言之,我想定义的绑定运算符与原始状态 monad 相同,只是我们绑定了 r1 和将参数传递给 r 的常量函数(以便将这两个操作链接在一起) .但是 ghc 告诉我 a 是刚性类型变量……这是什么意思?我不能在一个绑定运算符中使用另一个绑定运算符?
如果是这样,那么有没有办法实现这样的绑定运算符?怎么样?
由于我是 Haskell 的新手(我想我可能对函数
有一个符号错误
\_ -> r
),欢迎大家提出意见和参考,在此先致谢。
P.S。我对数据类型 SM 和类型构造函数 SMN 使用了不同的符号,以区分它们。
(>>=)
的类型是:
Monad m => m a -> (a -> m b) -> m b
由于您正在为 SM
编写实例,因此您实例中的绑定类型是
SM a -> (a -> SM b) -> SM b
请注意,a
和 b
都是完全不受限制的类型变量。这意味着无论我选择在其中放置什么类型,您提供的任何实现 都必须 有效。特别是,我可以为 a
和 b
选择 Int
:
SM Int -> (Int -> SM Int) -> SM Int
现在很清楚为什么您的实现不好:它将尝试将 Int
视为单子操作并对其调用 (>>=)
。
如果你希望能够在你的绑定中执行单子操作,你将不得不以某种方式谈论你的类型中的单子;例如,一种标准方法是定义
data SMT m a = SMT (S -> m (a, S))
并给出一个例子:
instance Monad m => Monad (SMT m) where -- ...
然后可以恢复正常的 SM
,如果你愿意,可以使用 Identity
monad 作为嵌套的 monad。
我正在尝试使用 Monad 编写 Haskell "number-guessing" 游戏程序,但我被卡住了:
我尝试了简单的状态 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)
而且我需要在元组 (a, S) 的 "IO-side" 上执行 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))
简而言之,我想定义的绑定运算符与原始状态 monad 相同,只是我们绑定了 r1 和将参数传递给 r 的常量函数(以便将这两个操作链接在一起) .但是 ghc 告诉我 a 是刚性类型变量……这是什么意思?我不能在一个绑定运算符中使用另一个绑定运算符?
如果是这样,那么有没有办法实现这样的绑定运算符?怎么样?
由于我是 Haskell 的新手(我想我可能对函数
\_ -> r
),欢迎大家提出意见和参考,在此先致谢。
P.S。我对数据类型 SM 和类型构造函数 SMN 使用了不同的符号,以区分它们。
(>>=)
的类型是:
Monad m => m a -> (a -> m b) -> m b
由于您正在为 SM
编写实例,因此您实例中的绑定类型是
SM a -> (a -> SM b) -> SM b
请注意,a
和 b
都是完全不受限制的类型变量。这意味着无论我选择在其中放置什么类型,您提供的任何实现 都必须 有效。特别是,我可以为 a
和 b
选择 Int
:
SM Int -> (Int -> SM Int) -> SM Int
现在很清楚为什么您的实现不好:它将尝试将 Int
视为单子操作并对其调用 (>>=)
。
如果你希望能够在你的绑定中执行单子操作,你将不得不以某种方式谈论你的类型中的单子;例如,一种标准方法是定义
data SMT m a = SMT (S -> m (a, S))
并给出一个例子:
instance Monad m => Monad (SMT m) where -- ...
然后可以恢复正常的 SM
,如果你愿意,可以使用 Identity
monad 作为嵌套的 monad。