State
jest alias typ bardziej uniwersalnym typem IndexedStateT
, który jest specjalnie zaprojektowany, aby reprezentować funkcje, które zmieniają rodzaj państwowej jako obliczeń państwowych:
type StateT[F[_], S, A] = IndexedStateT[F, S, S, A]
type State[S, A] = StateT[Id, S, A]
Chociaż to nie jest możliwe napisanie modify[S, T]
użyciu State
, to możliwe IndexedState
(który jest innym typem alias IndexedStateT
że ustala rodzaj efektu do Id
):
import scalaz._, Scalaz._
def transform[S, T](f: S => T): IndexedState[S, T, Unit] =
IndexedState(s => (f(s),()))
Można nawet użyć tego w for
-comprehensions (które zawsze wydawały się trochę dziwne dla mnie, ponieważ monadycznych zmian typu między operacjami, ale działa):
val s = for {
a <- init[Int];
_ <- transform[Int, Double](_.toDouble)
_ <- transform[Double, String](_.toString)
r <- get
} yield r * a
, a następnie:
scala> s(5)
res5: scalaz.Id.Id[(String, String)] = (5.0,5.05.05.05.05.0)
W twoim przypadku można napisać coś takiego:
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),()))
, a następnie:
def contrivedAdd[L <: HList](n: Int) = for {
a <- init[S[L]]
_ <- addField('latestAdded, n)(_ + n)
r <- get
} yield r.total
(To nie może być najlepszym sposobem faktoringowych na kawałki operacji aktualizacji, ale to pokazuje, jak działa podstawowy pomysł.)
Warto również zauważyć, że jeśli nie dbają o reprezentujący transformacja stan jako stan obliczeń, można po prostu użyć imap
na byle State
:
init[S[HNil]].imap(s =>
S(1, field[Witness.`'latestAdded`.T](1) :: s.scratch)
)
nie pozwalają na skorzystanie z tych operacji kompozycyjnie w taki sam sposób, ale może to być wszystko, co potrzebne w niektórych sytuacjach ,
Jak o 'def modyfikować [S, T], (f: S => T): Stan [T, jednostka] = stan ((S S) => (F (a),()))'? – knutwalker
@knutwalker sugerujesz rozszerzenie 'State' i przeciążenia' Zmień '? – Sim
Nie, wystarczy napisać tę funkcję w dowolnym miejscu w kodzie.Nie ma potrzeby rozszerzania ani przeciążania czegokolwiek. – knutwalker