Scalaz State monad的modify具有以下签名:
def modify[S](f: S => S): State[S, Unit]
这允许状态被相同类型的状态替换,当状态包括无形值(例如 Record
,其类型随着添加新字段而改变)时,该状态不能很好地工作 . 在这种情况下,我们需要的是:
def modify[S, T](f: S => T): State[T, Unit]
什么是使Scalaz的State monad适应无形状态的好方法,以便人们可以使用记录而不是可怕的 Map[String, Any]
?
例:
case class S[L <: HList](total: Int, scratch: L)
def contrivedAdd[L <: HList](n: Int): State[S[L], Int] =
for {
a <- init
_ <- modify(s => S(s.total + n, ('latestAddend ->> n) :: s.scratch))
r <- get
} yield r.total
Update:
Travis答案的完整代码是here .
1 回答
State
是更通用类型IndexedStateT
的类型别名,它专门用于表示将状态类型更改为状态计算的函数:虽然无法使用
State
编写modify[S, T]
,但可以使用IndexedState
(这是IndexedStateT
的另一种类型别名,将效果类型修复为Id
):你甚至可以在
for
-comprehensions中使用它(这对我来说似乎有点奇怪,因为monadic类型在操作之间改变,但它有效):然后:
在你的情况下,你可能写这样的东西:
然后:
(这可能不是分解更新操作的最佳方法,但它显示了基本思想的工作原理 . )
它关心将状态转换表示为状态计算,你可以在任何旧的
State
上使用imap
:这不允许您以相同的方式在组合上使用这些操作,但在某些情况下可能只需要它们 .