Scala 具有无形状状态单元组的状态转换
Scalaz State monad的签名如下:Scala 具有无形状状态单元组的状态转换,scala,scalaz,shapeless,state-monad,scalaz7,Scala,Scalaz,Shapeless,State Monad,Scalaz7,Scalaz State monad的签名如下: def modify[S](f:S=>S):状态[S,单位] 这允许将状态替换为同一类型的状态,当状态包含一个不成形的值(如记录),其类型随着新字段的添加而改变时,该状态将无法正常工作。在这种情况下,我们需要的是: def modify[S,T](f:S=>T):状态[T,单位] 有什么好方法可以使Scalaz的State monad使用不成形状态,这样就可以使用记录,而不是可怕的映射[String,Any] 例如: 案例类S[L状态是更通用
def modify[S](f:S=>S):状态[S,单位]
这允许将状态替换为同一类型的状态,当状态包含一个不成形的值(如记录
),其类型随着新字段的添加而改变时,该状态将无法正常工作。在这种情况下,我们需要的是:
def modify[S,T](f:S=>T):状态[T,单位]
有什么好方法可以使Scalaz的State monad使用不成形状态,这样就可以使用记录,而不是可怕的映射[String,Any]
例如:
案例类S[L状态
是更通用的类型
IndexedStateT的类型别名,专门设计用于表示将状态类型更改为状态计算的函数:
type StateT[F[_], S, A] = IndexedStateT[F, S, S, A]
type State[S, A] = StateT[Id, S, A]
虽然无法使用状态编写修改[s,T]
,但可以使用索引状态
(这是索引状态
的另一个类型别名,将效果类型固定为Id
):
您甚至可以在中使用它来理解(这对我来说总是有点奇怪,因为一元类型在操作之间会发生变化,但它可以工作):
在您的情况下,您可以这样写:
import shapeless._, shapeless.labelled.{ FieldType, field }
case class S[L <: HList](total: Int, scratch: L)
def addField[K <: Symbol, A, L <: HList](k: Witness.Aux[K], a: A)(
f: Int => Int
): IndexedState[S[L], S[FieldType[K, A] :: L], Unit] =
IndexedState(s => (S(f(s.total), field[K](a) :: s.scratch), ()))
这不允许您以相同的方式组合使用这些操作,但在某些情况下,它可能是您所需要的全部。如何def modify[S,t](f:S=>t):State[t,Unit]=State((S:S)=>(f(S),())
?@knutwalker您是否建议扩展状态
并重载修改
?不,只需在代码中的任意位置编写此函数。无需扩展或重载任何内容。您的答案除了优雅之外,还包含一块整洁的小宝石,即扩展记录的添加字段
唱一个键和一个值。见证和字段[K](a)
的组合在读取不成形源时不明显。
val s = for {
a <- init[Int];
_ <- transform[Int, Double](_.toDouble)
_ <- transform[Double, String](_.toString)
r <- get
} yield r * a
scala> s(5)
res5: scalaz.Id.Id[(String, String)] = (5.0,5.05.05.05.05.0)
import shapeless._, shapeless.labelled.{ FieldType, field }
case class S[L <: HList](total: Int, scratch: L)
def addField[K <: Symbol, A, L <: HList](k: Witness.Aux[K], a: A)(
f: Int => Int
): IndexedState[S[L], S[FieldType[K, A] :: L], Unit] =
IndexedState(s => (S(f(s.total), field[K](a) :: s.scratch), ()))
def contrivedAdd[L <: HList](n: Int) = for {
a <- init[S[L]]
_ <- addField('latestAdded, n)(_ + n)
r <- get
} yield r.total
init[S[HNil]].imap(s =>
S(1, field[Witness.`'latestAdded`.T](1) :: s.scratch)
)