State
è un tipo alias per un tipo più generico IndexedStateT
che è specificamente progettato per rappresentare le funzioni che cambiano il tipo di stato come i calcoli di stato:
type StateT[F[_], S, A] = IndexedStateT[F, S, S, A]
type State[S, A] = StateT[Id, S, A]
Anche se non è possibile scrivere il modify[S, T]
utilizzando State
, è possibile con IndexedState
(che è un altro tipo alias per IndexedStateT
che fissa il tipo di effetto a Id
):
import scalaz._, Scalaz._
def transform[S, T](f: S => T): IndexedState[S, T, Unit] =
IndexedState(s => (f(s),()))
È anche possibile utilizzare questo in for
-comprehensions (che è sempre sembrato un po 'strano per me, dal momento che i cambiamenti di tipo monadici tra le operazioni, ma funziona):
val s = for {
a <- init[Int];
_ <- transform[Int, Double](_.toDouble)
_ <- transform[Double, String](_.toString)
r <- get
} yield r * a
E poi:
scala> s(5)
res5: scalaz.Id.Id[(String, String)] = (5.0,5.05.05.05.05.0)
Nel tuo caso si potrebbe scrivere qualcosa del genere:
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),()))
E poi:
def contrivedAdd[L <: HList](n: Int) = for {
a <- init[S[L]]
_ <- addField('latestAdded, n)(_ + n)
r <- get
} yield r.total
(questo potrebbe non essere il modo migliore di factoring i pezzi di l'operazione di aggiornamento, ma dimostra come funziona l'idea di base.)
E 'anche interessante notare che se non si preoccupano che rappresenta il trasformazione stato come un calcolo dello stato, si può semplicemente utilizzare imap
su qualsiasi vecchio State
:
init[S[HNil]].imap(s =>
S(1, field[Witness.`'latestAdded`.T](1) :: s.scratch)
)
Questo non consente l'utilizzo di queste operazioni compositivo nello stesso modo, ma può essere tutto ciò che serve in alcune situazioni .
Come dire 'def modificare [S, T] (f: S => T): Stato [T, Unità] = Stato ((s: S) => (f (s),()))'? – knutwalker
@knutwalker stai suggerendo di estendere 'State' e sovraccaricare' modify'? – Sim
No, basta scrivere questa funzione in qualsiasi punto del codice.Non è necessario estendere o sovraccaricare nulla. – knutwalker