【问题标题】:trouble with state monad composition状态单子组成的问题
【发布时间】:2012-09-20 15:36:06
【问题描述】:

我正在尝试http://www.haskell.org/haskellwiki/State_Monad#Complete_and_Concrete_Example_1给出的示例

这如何使解决方案可组合超出了我的理解。这是我尝试过的,但我得到如下编译错误:

Couldn't match expected type `GameValue -> StateT GameState Data.Functor.Identity.Identity b0'
            with actual type `State GameState GameValue'
In the second argument of `(>>=)', namely `g2'
In the expression: g1 >>= g2
In an equation for `g3': g3 = g1 >>= g2
Failed, modules loaded: none.

这里是代码:见最后几行

module StateGame where
import Control.Monad.State

type GameValue = Int
type GameState = (Bool, Int)

-- suppose I want to play one game after the other
g1 = playGame "abcaaacbbcabbab"
g2 = playGame "abcaaacbbcabb"
g3 = g1 >>= g2

m2 = print $ evalState g3 startState

playGame :: String -> State GameState GameValue
playGame []     = do
    (_, score) <- get
    return score

playGame (x:xs) = do
    (on, score) <- get
    case x of
         'a' | on -> put (on, score + 1)
         'b' | on -> put (on, score - 1)
         'c'      -> put (not on, score)
         _        -> put (on, score)
    playGame xs

startState = (False, 0)

main str = print $ evalState (playGame str) startState

【问题讨论】:

  • 我建议至少为顶级函数编写显式类型签名,也许还可以为您不确定类型的任何其他术语编写显式类型签名。它有助于定位错误,并了解类型系统如何更好地工作。

标签: haskell state monads composition


【解决方案1】:

您可以通过两种方式组合您的两个游戏。第一种选择是在第一场比赛之后运行第二场比赛,从一个新鲜的状态开始。您可以使用:

main = do
    print $ evalState g1 startState
    print $ evalState g2 startState

或者,您可以让第二场比赛从第一场比赛结束的地方开始。您可以使用:

g3 = do
    g1
    g2

...这只是语法糖:

g3 = g1 >> g2

...并运行它:

main = print $ evalState g3 startState

【讨论】:

  • 谢谢。你能举一个需要“>>=”的组成的例子吗?另外,这种类型的g3是什么? g3 :: StateT GameState Data.Functor.Identity.Identity GameValue
  • @user1308560 是:main = getLine >>= putStrLn。这是 main = do { x You could have invented monads.
  • @user1308560 另外,StateT Identity 与 State 相同。
  • 再次感谢。抱歉没有更具体,但我想要一个“>>=”的例子,以防 State monad 而不是 IO。另外,如果 StateT Identity 与 State 相同,那么所有乱码“StateT GameState Data.Functor.Identity.Identity GameValue”呢?
  • @user1308560 随时提问!我一点都不介意!仅State 的示例将是:get &gt;&gt;= put :: State s (),在do 表示法中将是:do { x &lt;- get; put x }。每次您使用 do 表示法时,它都会在后台脱糖到 (&gt;&gt;=)。例如,在您编写do { (_, score) &lt;- get; return score } 时,在您的playGame 函数中,它被转换为:get &gt;&gt;= \(_, score) -&gt; return score。我将在第二条评论中回答您的第二个问题。
【解决方案2】:
g1 = playGame "abcaaacbbcabbab"
g2 = playGame "abcaaacbbcabb"
g3 = g1 >>= g2

g1g2 都是 State GameState GameValue 类型。但是(&gt;&gt;=) 有类型

(>>=) :: Monad m => m a -> (a -> m b) -> m b

因此它的第二个参数必须是一个函数。如果第一个参数是g1,则函数必须有类型

GameValue -> State GameState b

这是错误消息中的“预期类型”。但是g2 有一个不同的类型,那就是“实际类型”。

g3 的定义中你想要的组合子是(&gt;&gt;) :: Monad m =&gt; m a -&gt; m b -&gt; m b

g3 = g1 >> g2

【讨论】:

    猜你喜欢
    • 2019-06-06
    • 1970-01-01
    • 1970-01-01
    • 2011-04-24
    • 2020-04-15
    • 2017-08-16
    • 2020-10-23
    • 2012-11-30
    • 2018-10-20
    相关资源
    最近更新 更多