Skip to content
Dinko Srkoč edited this page Aug 7, 2011 · 3 revisions

State monad may be used when there is a sequence of operations that depend on a shared state. That state is then passed around and changed as needed. Monadic functions receive state and should return a [state, result] tuple.

For example, let's show how to solve the game of Fizzbuzz using state monad.

We should print the numbers from 1 to 100, but replace every multiple of 3 with "Fizz", every multiple of 5 with "Buzz", and for numbers that are multiples of both 3 and 5 print "FizzBuzz".

import static hr.helix.monadologie.MonadComprehension.foreach
import static hr.helix.monadologie.monads.State.state
import static hr.helix.monadologie.monads.State.init

def fizz = { it % 3 ? "" : "Fizz" },
    buzz = { it % 5 ? "" : "Buzz" }
    
def fizzbuzz = foreach {
    a = takeFrom { init() }
    b = takeFrom { state { s -> [fizz(a), a] }}
    c = takeFrom { state { s -> [s + buzz(b), b] }}
    yield { c }
}

(1..100).each {
    def fb = fizzbuzz(it)
    println fb[0] ?: fb[1]
}

In the example from the What Is a Monad we're depositing and withdrawing amounts from the account. The same functionality can be accomplished without Account monad:

import static hr.helix.monadologie.MonadComprehension.foreach
import static hr.helix.monadologie.monads.State.state

def withdraw = { amt -> state { s -> [s - amt, s] }},
    deposit  = { amt -> state { s -> [s + amt, s] }}

def acc = foreach {
    amt1 = takeFrom { deposit 15 }
    amt2 = takeFrom { withdraw 9 }
    yield { amt2 }
}

assert acc(11)[0] == 11 + 15 - 9

Clone this wiki locally