uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

GroovyでStateモナドを書いてみる

4年前に、GroovyでMaybe Monadを書いてみた。という記事を書きましたが、続編としてStateモナドをGroovyで書いてみます。
いかに当時わかってなかったかが判りました。

abstract class Monad {
    abstract Monad bind(Closure c);
    Monad rightShiftUnsigned(Closure c) { // Haskell's >>=
        bind(c)
    }
    abstract Monad bind0(Monad m);
    Monad rightShift(Monad m) { // Haskell's >>
        bind0(m)
    }
}

class State extends Monad {
    Closure runState // runState :: s -> [a,s]
    State(Closure runState) {
        this.runState = runState
    }
    @Override
    State bind(Closure funcReturnsState) { // bind :: State s a -> (a -> State s b) -> State s b
        return new State({ oldState ->
            def (returnValue, newState) = runState(oldState)
            funcReturnsState(returnValue).runState(newState)} )
    }
    @Override
    State bind0(Monad/*State*/ state) { // bind0 :: State s a -> State s b -> State s b
        return new State({ oldState ->
            def (_, newState) = runState(oldState)
            state.runState(newState)})
    }
    static State Return(x) { // Return :: a -> State s a
        new State({ s -> [x, s] })
    }
}

def push(n) { new State({stack-> stack.push(n); [null, stack]})}
pop = new State({stack-> [stack.pop(), stack]})

stackManip = push(3) >>
             push(4) >>
             pop >>> { x ->
             pop >>> { y ->
             push(x+y) >>
             pop
             }}

(value, stack) = stackManip.runState([])
assert value == 7
assert stack == []

モナドは別言語で作ってみないと結局理解できませんね〜。少なくとも私はそうでした。
次は「IOモナドをGroovyで書いてみる」行きます。

c.f.
uehaj.hatenablog.com


(追記)id:kmizushimaさんがScalaでStateモナドを書いているのを発見(笑