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モナドを書いているのを発見(笑