2015-11-07 4 views
0

Je travaille avec des Stream imbriquées s et que vous souhaitez utiliser la syntaxe de compréhension avec eux:Travailler avec Streams enveloppées dans Options

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

Cependant, la fonction retourne makeBs un Option[Stream[B]]. Je voudrais que le Option soit déballé automatiquement. En outre, je voudrais que la fonction entière retourne None si makeBs échoue. Donc la nouvelle fonction ressemblerait à ceci:

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

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

Le seul changement est le type de la fonction.

Comment puis-je accomplir quelque chose comme ça? Peut StreamingT de chats ou StreamT de scalaz aide ici?

Certains types sont flexibles. makeBs peut être fait pour retourner Stream[Option[B]] au lieu de Option[Stream[B]] si cela rendrait les choses plus simples.

Je dois utiliser le type scala standard lib Stream.

Répondre

1

Imaginons que la mise en œuvre

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) 

Supposons maintenant

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 

seront évaluées comme

Certains (flux ((1,1), (3333), (5 , 55555)))

2

Une autre façon de le faire est d'utiliser traverseM de scalaz:

import scalaz._, Scalaz._ 

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

La signature principale de traverseM est traverseM(fa: F[A])(f: A => G[F[B]]): G[F[B]] (F devrait avoir des instances de Traverse et Bind et G devrait avoir une instance de Applicative). Dans ce cas F est Stream, G est Option, et B dans la signature est (A, B) de votre exemple.

Donc, si vous appelez traverseM sur Stream[A], et que vous voulez revenir Option[Stream[(A, B)]], vous devez passer une fonction A => Option[Stream[(A, B)]] - c'est naturellement makeBs, suivie d'une carte profonde qui fait (A, B) paires.

Les fonctions avec le suffixe M (filterM, traverseM, foldLeftM, etc.) sont généralement très utiles lorsque vous souhaitez combiner plusieurs contextes différents, mais sans boilerplate des transformateurs monade.