【问题标题】:Propagation of State Monad状态单子的传播
【发布时间】:2011-03-22 00:31:02
【问题描述】:

我有以下功能可以在我的游戏世界的“图形”的“边缘”周围走动。它改变了世界的状态——特别是玩家的位置。我还需要报告一条消息,提醒玩家他们的位置发生了变化。

所以我可以返回一个 (message, newWorld) 元组,也可以使用 State monad。 (对吧?我是新手。)

这是我对 monad 方法的尝试:

walk dir = do
  world <- get
  let attempt = filter (\e -> edgeDirection e == dir) $ edges
      edges = (worldEdges world) M.! playerLoc
      playerLoc = playerLocation $ worldPlayer world
  case attempt of
    [] -> return "You can't go that way."
    (edge : _) -> do
      put world' 
      return message
        where world' = world { worldPlayer = player' }
              player' = (worldPlayer world) { playerLocation = loc }
              loc = edgeLocation edge
              message = "You go " ++ (downcase $ show dir)

问题是,现在 调用 walk 的函数有一个 State monad 需要处理。我是在 runState 那里,还是让那个函数也使用 State monad,像这样:

parseWalk dir =
  let direction = case dir of
                  ('e' : _) -> Just East
                  ('n' : _) -> Just North
                  ('s' : _) -> Just South
                  ('w' : _) -> Just West
                  ('u' : _) -> Just Up
                  ('d' : _) -> Just Down
                  _         -> Nothing
  in case direction of
    Just d -> walk d
    Nothing -> return "You can't go that way"

那么parseWalk的调用者呢,等等?我应该尽量让这个 State monad 尽可能长时间地传播吗?我应该在我的类型签名中看到很多 MonadState ... 吗?

【问题讨论】:

  • 由于您正在遍历和修改大型数据结构,您可能希望使用 Zipper。

标签: haskell state monads


【解决方案1】:

这是一种思考方式:runState 需要一个初始状态作为其参数。在您的代码中,这个初始状态在哪里可用?这就是 state monad 需要传播的距离。

请注意,runState 封装了有状态计算,因此如果您有两个并排的 runState 计算,它们将不会看到彼此的状态(除非您将结果从一个传递到另一个。)这也应该给你一个提示,runState 需要“向上”多远。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    相关资源
    最近更新 更多