2011-10-16 7 views
14

Sto cercando di capire come utilizzare StateT per combinare due trasformatori di stato State in base a un commento sulla mia risposta Scalaz state monad examples.scalaz Elenco [StateT] .sequence - impossibile trovare il valore implicito per il parametro n: scalaz.Applicativo

Sembra che sia molto vicino ma ho riscontrato un problema durante il tentativo di applicare sequence.

import scalaz._ 
import Scalaz._ 
import java.util.Random 

val die = state[Random, Int](r => (r, r.nextInt(6) + 1)) 

val twoDice = for (d1 <- die; d2 <- die) yield (d1, d2) 

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) 
} 

type StateMap[x] = State[Map[Int,Int], x] 

val diceAndFreqSum = stateT[StateMap, Random, Int]{ random => 
    val (newRandom, dice) = twoDice apply random 
    for (sum <- freqSum(dice)) yield (newRandom, sum) 
} 

così ho ottenuto fino ad avere un StateT[StateMap, Random, Int] che posso scartare con mappa iniziali stati casuali e vuoti:

val (freq, sum) = diceAndFreqSum ! new Random(1L) apply Map[Int,Int]() 
// freq: Map[Int,Int] = Map(9 -> 1) 
// sum: Int = 9 

Ora vorrei generare un elenco di quelli StateT e utilizzare sequence in modo che io possa chiamare list.sequence ! new Random(1L) apply Map[Int,Int](). Ma quando provo questo ottengo:

type StT[x] = StateT[StateMap, Random, x] 
val data: List[StT[Int]] = List.fill(10)(diceAndFreqSum) 
data.sequence[StT, Int] 

//error: could not find implicit value for parameter n: scalaz.Applicative[StT] 
      data.sequence[StT, Int] 
        ^

Qualche idea? Posso usare un po 'di aiuto per l'ultimo tratto - assumendo che sia possibile.

+0

Non capisco proprio perché non usi Scala's Random. –

+0

@ DanielC.Sobral, Scala ha una classe Random ?! Oh sì, funzionerebbe altrettanto bene. Non è materiale per la mia domanda, quindi lascerò 'java.util.Random'. – huynhjl

risposta

9

Ah guardando lo scalaz Monad source, ho notato che c'era un implicit def StateTMonad che conferma che StateT[M, A, x] è una monade per il parametro tipo x. Anche monadi sono applicativi, che è stato confermato, cercando in the definition of the Monad tratto e colpendo nel REPL:

scala> implicitly[Monad[StT] <:< Applicative[StT]] 
res1: <:<[scalaz.Monad[StT],scalaz.Applicative[StT]] = <function1> 

scala> implicitly[Monad[StT]] 
res2: scalaz.Monad[StT] = [email protected] 

Quindi questo mi ha dato l'idea di definire un implicito Applicative[StT] per aiutare il compilatore:

type StT[x] = StateT[StateMap, Random, x] 
implicit val applicativeStT: Applicative[StT] = implicitly[Monad[StT]] 

Questo ha fatto il trucco:

val data: List[StT[Int]] = List.fill(10)(diceAndFreqSum) 
val (frequencies, sums) = 
    data.sequence[StT, Int] ! new Random(1L) apply Map[Int,Int]() 

// frequencies: Map[Int,Int] = Map(10 -> 1, 6 -> 3, 9 -> 1, 7 -> 1, 8 -> 2, 4 -> 2) 
// sums: List[Int] = List(9, 6, 8, 8, 10, 4, 6, 6, 4, 7)