所以我试图通过在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 >>=
}
}