你如何使用scalaz定义自己的状态monad?

时间:2015-03-18 23:15:13

标签: scala monads scalaz monad-transformers state-monad

所以我试图通过在scalaz中扩展Monad特征来定义我自己的状态monad。我知道我正在重新发明轮子,但我正在努力学习有关scala和scalaz的更多信息。我的代码如下:

package pure
import scalaz._, Scalaz._

object StateUtil {
  sealed trait State[S, A] { self =>
    def unit[A](a : A) : State[S, A] = StateM(s => (a, s))
    def runState(s : S) : (A, S) 
    def flatMap[B](f : A => State[S, B]) : State[S, B] = {
        val stateFun = (s : S) => {
          val (v, ss) = self.runState(s)
          f(v).runState(ss)
        }
        StateM(stateFun)
    }

    def map[B](f : A => B) : State[S, B] = flatMap(f andThen (unit _))
  }

  case class StateM[S, A](run : S => (A, S)) extends State[S, A] {
    def runState(s : S) : (A, S) = run(s)
  }

  class StateMonad[S]() extends Monad[({type St[A] = State[S, A]})#St] {
    def point[A](a : => A) : State[S, A] = StateM(s => (a, s))
    def bind[A, B](prev : State[S, A])(f : A => State[S, B]) : State[S, B] = prev flatMap f
    def apply[A](a : => A) : State[S, A] = point(a)
  }

  def put[S](s : S) : State[S, Unit] = StateM(_ => ((), s))

  def get[S]: State[S, S] = StateM(s => (s, s))


}

我正在尝试实现与名为stackyStack的haskell函数相同的行为(代码在下面的注释中)。问题是get方法返回State[S, S]类型的东西,我不能使用scalaz的>>=运算符。但我不知道如何做到这一点。

我甚至不确定这是否是你用scalaz定义自己的monad的方式。如果我想在scala中复制do语法,我还缺少什么?

object main {
  import pure.StateUtil._

  /*
   *  stackyStack :: State Stack ()  
        stackyStack = do  
          stackNow <- get  
          if stackNow == [1,2,3]  
            then put [8,3,1]  
            else put [9,2,1]  
   */
   type Stack = List[Int]
   def stacky : State[Stack, Unit] = {
     // won't compile, because get returns something of type State[S, S],            
     // and the bind operator is not a memeber of the State trait I defined
     get >>=
   }


}

0 个答案:

没有答案