状态单子:用一种模式交换另一种模式?

发布于 2024-09-13 03:02:30 字数 483 浏览 11 评论 0原文

因此,我正在用 Haskell 编写一个游戏,并将玩家的回合表示为一系列与各个回合阶段相关的状态改变函数。最初,这看起来像:

let game'  = phase1 game
    game'' = phase2 game'
-- etc.

国家独子的主要候选人,对吧?这导致更优雅:

do
  phase1
  phase2
-- etc.

但是,似乎我必须更改 phase1phase2 等,以从样板“状态获取”步骤开始:

phase1 = get >>= \game -> -- ...

I'我希望有一种方法可以将其抽象出来,这样我就可以避免调用者和被调用者都出现样板。我只是太新了,不知道这种方式是什么(这是我的第一个真正的 Haskell 项目)。有什么建议吗?

So I'm writing a game in Haskell, and I'm expressing a player's turn as a series of state-altering functions that correlate to various turn phases. Originally, this looks something like:

let game'  = phase1 game
    game'' = phase2 game'
-- etc.

Prime candidate for State monadosity, right? This leads to the more elegant:

do
  phase1
  phase2
-- etc.

However, then it seems like I have to change phase1, phase2, et al to begin with a boilerplate "State getting" step:

phase1 = get >>= \game -> -- ...

I'm hoping there's a way to abstract this out, so I can avoid boilerplate on both the caller and the callee. I'm just too new to know what this way is (this is my first real Haskell project). Any advice?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

如若梦似彩虹 2024-09-20 03:02:30

嗯,它还不是很单调。这是 Endo 幺半群。这会导致更优雅

game = mconcat [ phase1, phase2, ... ]

,并且每个阶段都会被写入:

phase1 = Endo $ \game -> ...

如果您需要在每个阶段中返回一些附加数据以及新状态,那么您将转向 monad。在这种情况下,一个简单的函数将使您的样板更容易忍受:

phase :: (GameState -> GameMonad a) -> GameMonad a
phase f = f =<< get

然后编写一个阶段:

phase1 = phase $ \game -> do ...

但是如果您想使用状态,您可能必须给它一个名称(除非您可以通过以下方式欺骗pointfreeness:使用 获取 或 < a href="http://hackage.haskell.org/package/data-accessor" rel="nofollow noreferrer">data-accessor),在这种情况下,你不能得到比函数更简洁的东西和一个 lambda。

Well, it's not quite monadosic yet. This is a prime candidate for an Endo monoid. This leads to the more elegant

game = mconcat [ phase1, phase2, ... ]

And each phase is written:

phase1 = Endo $ \game -> ...

You would move to a monad if you needed to return a some additional data along with the new state in each phase. In that case a simple function will make your boilerplate more tolerable:

phase :: (GameState -> GameMonad a) -> GameMonad a
phase f = f =<< get

And then a phase is written:

phase1 = phase $ \game -> do ...

But if you want to use the state, you are probably going to have to give it a name (unless you can finagle pointfreeness by, say, using gets or data-accessor), and in that case you can't get much terser than a function and a lambda.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文