2015-10-20 5 views
0

Я пытаюсь понять и устроиться с государственной Монадой, поэтому я в основном следую, копируя уже существующий пример. «Государство» - это просто дверь, которая открывается, если она нажимается, когда закрывается и закрывается, когда выталкивается, если она открыта. Если он нажат, когда он открыт или запущен, когда он закрыт, он ничего не делает. Таким образом, приведенный ниже код работает так, как ожидалось.Отвлекся, пытаясь понять состояние Монады

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 (Push, Door(op)) => if (op) door else Door(false) 

который я думаю, было бы то же самое ... // Это приводит к:

Это должно быть что-то действительно суеверное с моей стороны, но я не могу найти, и у меня нет другого объяснения того, что происходит. Кто-то может помочь?

Спасибо.

+1

Вы на самом деле замешан смыслом Тяговых и толкающим в вашем коде. В комментариях говорится, что '// Push to open, pull to close'. Хорошо, вы начали с двери, которая закрыта по умолчанию и после открытия первой итерационной двери ('Push to open'). –

ответ

1

Как Artsiom упоминается в комментариях, смешивает Push/Pull и Door(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) 
+0

Извините, ребята, за пронзительную ошибку. Устал, я думаю, –

+0

Спасибо за потрясающую экспозицию и пример со сказазом! Очень полезно. –

Смежные вопросы