在试图了解国家Monad时分心

时间:2015-10-20 18:12:15

标签: scala case-class state-monad

我试图理解并对State Monad感到满意,所以我基本上都是通过复制一个预先存在的例子。 '州'只有一扇门在关闭时推开,在拉开时关闭,如果它打开的话。如果它在打开时推动或在关闭时拉动,它什么都不做。所以下面的代码似乎按预期工作。

def main(args: Array[String]): Unit = {
import Monad._

// Push to open, pull to close
case class Door(open: Boolean = false)
trait Action
case object Push extends Action
case object Pull extends Action

def update: Action => Door => Door = action => door => {
  val curr = (action, door)
  println(curr)
  curr match {
    case (Push, Door(op)) => if (op) door else Door(!op)
    case (Pull, Door(op)) => if (op) Door(!op) else door
  }
}

val sm = stateMonad[Door] // Code for 'stateMonad' not shown

def simulate(inputs: List[Action]) = for {
  _ <- sm.sequence(inputs map (a => State.modify(update(a))))
  s <- State.get
} yield ()

val actions = List(Push, Pull, Pull, Push)

val r = simulate(actions).run(Door())

println(r) }

//上面的代码导致:

(Push,Door(false))
(Pull,Door(true))
(Pull,Door(false))
(Push,Door(false))
((),Door(true))

但是,如果我将第一个case语句更改为:

case (Push, Door(op)) => if (op) door else Door(false)

我认为这将是同样的事情...... //结果是:

(Push,Door(false))
(Pull,Door(false))
(Pull,Door(false))
(Push,Door(false))
((),Door(false))

这对我来说真的很棒,但是我找不到,否则我就无法解释发生了什么。有人可以帮忙吗?

感谢。

1 个答案:

答案 0 :(得分:1)

与评论中提到的Artsiom一样,您混合了Push / PullDoor(true) / Door(false)

如果门是打开的话,模式匹配可能更容易:

curr match {
  case (Push, Door(false)) => Door(true)
  case (Pull, Door(true))  => Door(false)
  case _                   => door
}

更明确的是将一些方法添加到Door

case class Door(isOpen: Boolean = false) {
  def isClosed = !isOpen
  def open = copy(isOpen = true)
  def close = copy(isOpen = false)
}

然后,模式匹配可能如下所示:

action match {
  case Push if door.isClosed => door.open
  case Pull if door.isOpen   => door.close
  case _                     => door
}

使用scalaz State检查:

import scalaz._, Scalaz._

def updateDoor(action: Action): State[Door, (Action, Door)] = 
  State(door => action match {
    case Push if door.isClosed => (door.open,  (action, door))
    case Pull if door.isOpen   => (door.close, (action, door))
    case _                     => (door,       (action, door))
  })

val actions = List(Push, Pull, Pull, Push) 
val (end, steps) = actions.traverseU(updateDoor).run(Door())

这给你的第一个例子提供了类似的输出:

scala> steps.foreach(println)
(Push,Door(false))
(Pull,Door(true))
(Pull,Door(false))
(Push,Door(false))

scala> println(end)
Door(true)