/ / Praca ze strumieniami w Opcjach - scala, scalaz, monadransformatory, scala-cats

Praca ze strumieniami w Opcjach - scala, scalaz, monadransformatory, scala-cats

Pracuję z niektórymi zagnieżdżonymi Streams i chciałby użyć dla nich składni ze zrozumieniem:

def handleNestedStream(as : Stream[A]) : Stream[(A, B)] = {
a <- as
b <- makeBs(a)
} yield (a, b)

Jednakże makeBs funkcja zwraca Option[Stream[B]]. Chciałbym Option do automatycznego rozpakowania. Ponadto chciałbym, aby cała funkcja powróciła None gdyby makeBs zawiedzie. Tak więc nowa funkcja będzie wyglądać mniej więcej tak:

def makeBs(a : A) : Option[Stream[B]] = { ... }

def handleNestedStream(as : Stream[A]) : Option[Stream[(A, B)]] = {
a <- as
b <- makeBs(a)
} yield (a, b)

Jedyna zmiana to rodzaj funkcji.

Jak mogę osiągnąć coś takiego? Mogą StreamingT od kotów lub StreamT od pomocy skalazu tutaj?

Niektóre typy są elastyczne. makeBs można powrócić Stream[Option[B]] zamiast Option[Stream[B]] Gdyby to było prostsze.

Muszę użyć standardowej biblioteki scala Stream rodzaj.

Odpowiedzi:

1 dla odpowiedzi № 1

Wyobraźmy sobie tę implementację

import scalaz._
import std.option._
import syntax.std.option._

type StreamO[X] = StreamT[Option,X]

def makeBs(a : A) : StreamO[B] = ???

def handleNestedStream(as : Stream[A]) : StreamO[(A, B)] = for {
a <- StreamT fromStream as.some
b <- makeBs(a)
} yield (a, b)

Przypuśćmy teraz

import syntax.monad._
type A = Int
type B = String
def makeBs(a : A) = for (x <- a.point[StreamO] if x % 2 == 1) yield x.toString * x

handleNestedStream(1 to 5 toStream).toStream

zostaną ocenione jako

Niektóre (Strumień ((1,1), (3,333), (555555))


2 dla odpowiedzi nr 2

Innym sposobem na to jest użycie traverseM od scalaz:

import scalaz._, Scalaz._

def handleNestedStream(as : Stream[A]) : Option[Stream[(A, B)]] =
as.traverseM(a => makeBs(a).map(_.map(a ->)))

Główny podpis traverseM jest traverseM(fa: F[A])(f: A => G[F[B]]): G[F[B]] (F powinny mieć instancje Traverse i Bind, i G powinien mieć instancję Applicative). W tym przypadku F jest Stream, G jest Option, i B w podpisie jest (A, B) z twojego przykładu.

Więc jeśli zadzwonisz traverseM na Stream[A]i chcę wrócić Option[Stream[(A, B)]], powinieneś przekazać mu funkcję A => Option[Stream[(A, B)]] - to jest naturalnie makeBs, a następnie głęboka mapa, która tworzy (A, B) pary.

Funkcje z sufiksem M (filterM, traverseM, foldLeftM, itp.) są na ogół całkiem przydatne, gdy chcesz łączyć kilka różnych kontekstów, ale bez tablicy transformatorów monad.