Je suppose, scalaz 7.0.x et les importations suivantes (voir la réponse de l'histoire de scalaz 6.x):
import scalaz._
import Scalaz._
L'état type est défini comme State[S, A]
où S
est le type de l'état et de l' A
est le type de la valeur décoré. La syntaxe de base pour créer une valeur de l'état de fait de l'utilisation de l' State[S, A]
fonction de:
// Create a state computation incrementing the state and returning the "str" value
val s = State[Int, String](i => (i + 1, "str"))
Pour exécuter l'état de calcul sur une valeur initiale:
// start with state of 1, pass it to s
s.eval(1)
// returns result value "str"
// same but only retrieve the state
s.exec(1)
// 2
// get both state and value
s(1) // or s.run(1)
// (2, "str")
L'état peut être enfilé à travers les appels de fonction. Pour ce faire, au lieu de Function[A, B]
, définissent Function[A, State[S, B]]]
. Utiliser l' State
de la fonction...
import java.util.Random
def dice() = State[Random, Int](r => (r, r.nextInt(6) + 1))
Puis l' for/yield
de la syntaxe peuvent être utilisés pour composer les fonctions de:
def TwoDice() = for {
r1 <- dice()
r2 <- dice()
} yield (r1, r2)
// start with a known seed
TwoDice().eval(new Random(1L))
// resulting value is (Int, Int) = (4,5)
Voici un autre exemple. Remplir une liste avec TwoDice()
état des calculs.
val list = List.fill(10)(TwoDice())
// List[scalaz.IndexedStateT[scalaz.Id.Id,Random,Random,(Int, Int)]]
Utilisation de la séquence pour obtenir un State[Random, List[(Int,Int)]]
. Nous pouvons fournir un alias de type.
type StateRandom[x] = State[Random,x]
val list2 = list.sequence[StateRandom, (Int,Int)]
// list2: StateRandom[List[(Int, Int)]] = ...
// run this computation starting with state new Random(1L)
val tenDoubleThrows2 = list2.eval(new Random(1L))
// tenDoubleThrows2 : scalaz.Id.Id[List[(Int, Int)]] =
// List((4,5), (2,4), (3,5), (3,5), (5,5), (2,2), (2,4), (1,5), (3,1), (1,6))
Ou nous pouvons utiliser sequenceU
qui permettra d'en déduire les types:
val list3 = list.sequenceU
val tenDoubleThrows3 = list3.eval(new Random(1L))
// tenDoubleThrows3 : scalaz.Id.Id[List[(Int, Int)]] =
// List((4,5), (2,4), (3,5), (3,5), (5,5), (2,2), (2,4), (1,5), (3,1), (1,6))
Un autre exemple, State[Map[Int, Int], Int]
pour calculer la fréquence de sommes sur la liste ci-dessus. freqSum
calcule la somme de la lance et compte fréquences.
def freqSum(dice: (Int, Int)) = State[Map[Int,Int], Int]{ freq =>
val s = dice._1 + dice._2
val tuple = s -> (freq.getOrElse(s, 0) + 1)
(freq + tuple, s)
}
Maintenant, utilisez parcourir pour appliquer freqSum
sur tenDoubleThrows
. traverse
est équivalent à map(freqSum).sequence
.
type StateFreq[x] = State[Map[Int,Int],x]
// only get the state
tenDoubleThrows2.copoint.traverse[StateFreq, Int](freqSum).exec(Map[Int,Int]())
// Map(10 -> 1, 6 -> 3, 9 -> 1, 7 -> 1, 8 -> 2, 4 -> 2) : scalaz.Id.Id[Map[Int,Int]]
Ou de façon plus succincte en utilisant traverseU
d'inférer les types:
tenDoubleThrows2.copoint.traverseU(freqSum).exec(Map[Int,Int]())
// Map(10 -> 1, 6 -> 3, 9 -> 1, 7 -> 1, 8 -> 2, 4 -> 2) : scalaz.Id.Id[Map[Int,Int]]
Notez que parce qu' State[S, A]
est un alias de type pour StateT[Id, S, A]
, tenDoubleThrows2 finit par être tapé comme Id
. J'utilise copoint
à la remettre en List
type.
En bref, il semble être la clé de l'utilisation de l'état est d'avoir des fonctions de retour d'une fonction de modification de l'état et le résultat réel de la valeur désirée... Avertissement: je n'ai jamais utilisé state
de la production de code, juste essayer d'obtenir une sensation pour elle.
Plus d'infos sur @ziggystar commentaire
J'ai renoncé à essayer en utilisant stateT
peut être quelqu'un d'autre peut montrer si StateFreq
ou StateRandom
peut être augmentée pour effectuer le combiné calcul. Ce que j'ai trouvé, au contraire, est que la composition des deux transformateurs peuvent être combinées:
def stateBicompose[S, T, A, B](
f: State[S, A],
g: (A) => State[T, B]) = State[(S,T), B]{ case (s, t) =>
val (newS, a) = f(s)
val (newT, b) = g(a) apply t
(newS, newT) -> b
}
Elle est fondée sur l' g
être un paramètre de fonction prenant la suite du premier état du transformateur et le retour à un état du transformateur. Puis la suivante devrait fonctionner:
def diceAndFreqSum = stateBicompose(TwoDice, freqSum)
type St2[x] = State[(Random, Map[Int,Int]), x]
List.fill(10)(diceAndFreqSum).sequence[St2, Int].exec((new Random(1L), Map[Int,Int]()))