【发布时间】:2015-12-01 08:54:55
【问题描述】:
当我学习State Monad时,我不知道如何组合两个具有不同State返回类型的函数。
状态单子定义:
case class State[S, A](runState: S => (S, A)) {
def flatMap[B](f: A => State[S, B]): State[S, B] = {
State(s => {
val (s1, a) = runState(s)
val (s2, b) = f(a).runState(s1)
(s2, b)
})
}
def map[B](f: A => B): State[S, B] = {
flatMap(a => {
State(s => (s, f(a)))
})
}
}
两种不同的状态类型:
type AppendBang[A] = State[Int, A]
type AddOne[A] = State[String, A]
两种状态返回类型不同的方法:
def addOne(n: Int): AddOne[Int] = State(s => (s + ".", n + 1))
def appendBang(str: String): AppendBang[String] = State(s => (s + 1, str + " !!!"))
定义一个函数来使用上面的两个函数:
def myAction(n: Int) = for {
a <- addOne(n)
b <- appendBang(a.toString)
} yield (a, b)
我希望这样使用它:
println(myAction(1))
问题是myAction 不可编译,报错如下:
Error:(14, 7) type mismatch;
found : state_monad.State[Int,(Int, String)]
required: state_monad.State[String,?]
b <- appendBang(a.toString)
^
我该如何解决?我必须定义一些 Monad 转换器吗?
更新:问题可能不清楚,我举个例子
假设我想定义另一个函数,它在内部使用addOne 和appendBang。由于它们都需要现有状态,因此我必须将一些状态传递给它:
def myAction(n: Int)(addOneState: String, appendBangState: Int): ((String, Int), String) = {
val (addOneState2, n2) = addOne(n).runState(addOneState)
val (appendBangState2, n3) = appendBang(n2.toString).runState(appendBangState)
((addOneState2, appendBangState2), n3)
}
我必须一个一个地运行addOne和appendBang,手动传递和获取状态和结果。
虽然我发现它可以返回另一个State,但代码并没有太大改进:
def myAction(n: Int): State[(String, Int), String] = State {
case (addOneState: String, appendBangState: Int) =>
val (addOneState2, n2) = addOne(n).runState(addOneState)
val (appendBangState2, n3) = appendBang(n2.toString).runState( appendBangState)
((addOneState2, appendBangState2), n3)
}
由于我对它们不太熟悉,只是想知道有什么方法可以改进它。最大的希望是我可以使用for 理解,但不确定这是否可能
【问题讨论】:
-
您的
flatMap函数将State[S, A]转换为State[S, B],因此您不能在for comprehension 中更改状态类型。您甚至想如何从String转到Int? -
@PeterNeyens 谢谢,我的问题最好是:如果在我的函数中,我想使用返回不同状态单子的两个函数,我该怎么做?比如,如何将一些现有的状态传递给它,以及如何获取它们以供以后使用?
-
我不明白你的意思。您能否添加一个示例,说明您希望如何使用两个不同的
States? -
@PeterNeyens 刚刚更新,感谢回复
-
@PeterNeyens:他似乎想将他的两个状态函数从
A和B提升到State[(A,B), …]
标签: scala functional-programming state monads