/ / Zoznam [OptionT [Future, Int]] až OptionT [Future, List [A]] - Scala, Scalaz, Monad Transformers

Zoznam [MožnosťT [Budúcka, Int]] na možnosťT [Future, List [A]] - scala, scalaz, monadransformátory

Budujem budovu List z Int použitie asynchrónneho výpočtu na načítanie prvku:

(1 to n).map(anAsyncThingy).toList

kde anAsyncThingy výnos OptionT[Future, Int]

Výsledkom je teda typ List[OptionT[Future, Int]]

To, čo by som teraz rád získal, je OptionT[Future, List[A]]

Tu je môj najlepší pokus (pridám pár útržkov, aby mohol bežať v REPL)

import scalaz._; import Scalaz._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def anAsyncThingy(x: Int): OptionT[Future, Int] = x.point[Future].liftM[OptionT]

val res = OptionT {
Future.sequence {
(1 to 3).map(anAsyncThingy(_).run).toList
}.map(_.sequence)
}
res.map(println) // List(1, 2, 3)

Horeuvedené práce fungujú podľa očakávania, ale cítim, že existuje veľa priestoru na zlepšenie pomocou vhodných skeletových konštruktov, namiesto preskočenia a vyskočenia z monadových transfomérov.

Ako môžem dosiahnuť ten istý výsledok jednoduchším spôsobom?

odpovede:

4 pre odpoveď č. 1

Odpoveď som našiel sám po niekoľkých pokusoch:

val res = (1 to 3).map(anAsyncThingy).toList.sequenceU
res.map(println) // List(1, 2, 3)

Yay for scalaz!

mimochodom sequenceU je potrebný namiesto sequence pretože Scala nie je natoľko šikovný, aby zistil, kedy máš

OptionT[M, A]

ak opravíte parameter type (M na Future napríklad)

OptionT[Future, A]

má tvar M[_]

Kompilátor stále verí, že má M[_, _] tvar, pokiaľ nie je spoonfed (s škaredým typom lambda)

Tu je "scalaz" sequenceU kopy a rieši tento problém pomocou Unapply, Viac na túto tému tu.

aktualizovať

Podľa komentára Phadeja sequence ∘ map ≡ traverse, aby sa to dalo ešte skrátiť traverseU:

(1 to 3).toList.traverseU(anAsyncThingy)

Rovnaká myšlienka sequence proti sequenceU týka sa traverse proti traverseU, samozrejme.