0

我正在使用一些嵌套Stream的 s 并希望对它们使用 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从猫或StreamT斯卡拉兹那里得到帮助吗?

有些类型是灵活的。makeBs可以返回Stream[Option[B]],而不是Option[Stream[B]]让事情变得更简单。

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

4

2 回答 2

2

另一种方法是使用traverseMfrom scalaz

import scalaz._, Scalaz._

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

的主要签名traverseMtraverseM(fa: F[A])(f: A => G[F[B]]): G[F[B]](F应该有Traverseand的实例Bind,并且G应该有Applicative) 的实例。在这种情况下Fis StreamGis Option,并且B签名(A, B)来自您的示例。

因此,如果您调用traverseMStream[A]想要返回Option[Stream[(A, B)]],您应该向它传递一个函数A => Option[Stream[(A, B)]]——这很自然makeBs,然后是一个形成对的深度映射(A, B)

当您想要组合几个不同的上下文但没有 monad 转换器的样板时,带有后缀M( filterM, traverseM,等) 的函数通常非常有用。foldLeftM

于 2015-11-07T22:44:26.037 回答
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)))

于 2015-11-07T15:49:20.783 回答