如何堆叠State和IO monad

时间:2019-06-15 15:44:45

标签: scala functional-programming monads scala-cats

在Connect4游戏中:

  • 我们从一个空的网格开始
  • 两个玩家将x和o放置在网格上
  • 第一个在一行中获得4枚棋子的玩家获胜!
  • 这是一个基于文本的控制台游戏

我的想法是:

  • 在游戏的每个步骤中,网格都从一种状态过渡到另一种状态
  • 因此我需要使用State monad
  • 并且因为这是一个涉及io的基于控制台的应用程序
  • 在这种情况下,我还需要使用IO monad

这种想法正确吗?

假设以上内容正确,其中哪一项正确?

  • 类型StateInIO [S,A] = IO [State [S,A]]
  • 类型IOInState [S,A] =状态[S,IO [A]]

我赞成第二种选择,对我来说更有意义。

我可以用这种方式堆叠这些单子吗(状态,IO)?

2 个答案:

答案 0 :(得分:2)

猫中的

State实际上定义为monad变换器StateT[F[_], S, A]的类型别名,其中F[_]是效果类型。该别名用F[_]修复了Eval,因此看起来像type State[S, A] = StateT[Eval, S, A]。就您而言,您应该只定义自己的IO状态,例如type IOState[S, A] = StateT[IO, S, A]

StateT[IO, S, A]对应于IO[S => IO[(S, A)]],我认为它是更有用的堆栈,因为您现在可以轻松地使用此堆栈将代码与使用IO的其余应用程序连接起来。

在猫的国家文档中的interleaving effects部分中,您可以找到更多有关将状态monad与效果StateT叠加的monad的信息。

答案 1 :(得分:1)

我认为您应该只编写一个工作程序并在以后对其进行概括/重构,而不是过度努力。 您需要State[S, A]用于业务逻辑,IO[A]用于与控制台进行交互。但是您不必混合。

然后在编写用户交互循环的主类中,您可以利用StateT来统一这两种类型。

顺便说一下,IO[State[S,A]]看起来不是非常有用的类型。它说您可以从现实世界中读取State[S, A]State是一个函数。没有明智的方法可以从现实世界中读取功能。因此,很可能您需要功能不那么强大的产品。当然,在monad变形金刚的上下文中,这种类型是有意义的。