Un paio di settimane fa Dragisa Krsmanovic ha chiesto a question here su come utilizzare la monade gratuita in Scalaz 7 per evitare overflow dello stack in questa situazione (ho adattato un po 'il suo codice):Combinativo applicativo vs monadico e monad in Scalaz
import scalaz._, Scalaz._
def setS(i: Int): State[List[Int], Unit] = modify(i :: _)
val s = (1 to 100000).foldLeft(state[List[Int], Unit](())) {
case (st, i) => st.flatMap(_ => setS(i))
}
s(Nil)
ho pensato that just lifting a trampoline into StateT
dovrebbe funzionare:
import Free.Trampoline
val s = (1 to 100000).foldLeft(state[List[Int], Unit](()).lift[Trampoline]) {
case (st, i) => st.flatMap(_ => setS(i).lift[Trampoline])
}
s(Nil).run
Ma soffia ancora lo stack, quindi ho solo postato come commento.
Dave Stevens solo pointed out che sequenziamento con l'applicativo *>
invece della monade flatMap
in realtà funziona bene:
val s = (1 to 100000).foldLeft(state[List[Int], Unit](()).lift[Trampoline]) {
case (st, i) => st *> setS(i).lift[Trampoline]
}
s(Nil).run
(Beh, è super slow, naturalmente, perché questo è il prezzo da pagare per fare qualcosa di interessante come questo in Scala, ma almeno non c'è overflow dello stack.)
Cosa sta succedendo qui? Non penso che ci possa essere una ragione di principio per questa differenza, ma in realtà non ho idea di cosa potrebbe accadere nell'implementazione e non ho il tempo di scavare intorno al momento. Ma sono curioso e sarebbe bello se lo sapesse qualcun altro.
+1 e grazie, ma la mia comprensione è che il modo in cui il trampolino 'flatMap' reifica bind sul mucchio significa che saremmo stati al sicuro qui anche se non stessimo buttando via quel risultato? –
@cdk Non penso che questa sia la risposta. Scegli un altro operatore che dipende dal risultato di sinistra * e * richiede 'Applica' invece di' Bind'. per esempio. '| @ |' https://gist.github.com/drstevens/3ea464446ee59463af1e – drstevens