我正在使用一些嵌套的Stream
,并希望使用for comprehension语法:
def handleNestedStream(as : Stream[A]) : Stream[(A, B)] = {
a <- as
b <- makeBs(a)
} yield (a, b)
但是,makeBs
函数返回Option[Stream[B]]
。我希望Option
能够自动解包。另外,如果None
失败,我希望整个函数返回makeBs
。所以新函数看起来像这样:
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
类型。
答案 0 :(得分:2)
另一种方法是使用traverseM
中的scalaz
:
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
应该包含Traverse
和Bind
的实例,G
应该有一个实例Applicative
)。在这种情况下,F
为Stream
,G
为Option
,签名中的B
为(A, B)
。
因此,如果您在traverseM
上致电Stream[A]
,并希望返回Option[Stream[(A, B)]]
,则应将其传递给A => Option[Stream[(A, B)]]
函数 - 这自然是makeBs
,然后是一个使(A, B)
对成对的深度图。
带有后缀M
(filterM
,traverseM
,foldLeftM
等)的功能在您想要组合多个不同的上下文时通常非常有用,但没有monad变压器的样板。
答案 1 :(得分: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),(3,333),(5,55555)))