2015-11-07 57 views
0

我与一些嵌套Stream s工作,并想与他们使用的理解语法:与工作流包裹在选项

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

然而,makeBs函数返回一个Option[Stream[B]]。我想Option自动解包。另外,如果makeBs失败,我希望整个函数返回None。所以新功能看起来像这样:

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

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

唯一的变化是函数的类型。

我该如何做到这样?罐头StreamingT可以从scalaz或StreamT帮忙吗?

某些类型是灵活的。 makeBs可以返回Stream[Option[B]]而不是Option[Stream[B]],如果这样做会使事情变得更简单。

我需要使用scala标准lib Stream类型。

回答

1

让我们想象一下实现

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) 

假设现在

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 

将被评估为

一些(流((1,1),(3333),(5 ,55555)))

2

另一种方式做,这是使用traverseMscalaz

import scalaz._, Scalaz._ 

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

traverseM主要签名traverseM(fa: F[A])(f: A => G[F[B]]): G[F[B]]F应该有TraverseBind,并G情况下,应该有Applicative一个实例)。在这种情况下,FStream,GOptionB中的签名是(A, B)。如果你调用traverseMStream[A],并希望取回Option[Stream[(A, B)]]

所以,你应该通过它的功能A => Option[Stream[(A, B)]] - 这是自然makeBs,其次是深地图,使(A, B)对。

后缀MfilterMtraverseMfoldLeftM等)的功能通常是非常有用的,当你想几处不同的组合,但没有单子变压器的样板。