使用包含在选项中的流
Working with Streams wrapped in Options
我正在处理一些嵌套的 Stream
s 并且想对它们使用 for comprehension 语法:
def handleNestedStream(as : Stream[A]) : Stream[(A, B)] = {
a <- as
b <- makeBs(a)
} yield (a, b)
但是,makeBs
函数 return 是一个 Option[Stream[B]]
。我希望 Option
自动展开。此外,如果 makeBs
失败,我希望整个函数 return 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)
唯一的变化是函数的类型。
我怎样才能完成这样的事情?来自 cats 的 StreamingT
或来自 scalaz 的 StreamT
可以帮助解决这个问题吗?
有些类型是灵活的。 makeBs
可以改为 return Stream[Option[B]]
而不是 Option[Stream[B]]
如果这样可以使事情更简单。
我需要使用 scala 标准库 Stream
类型。
让我们想象一下实现
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
将被评估为
Some(Stream((1,1), (3,333), (5,55555)))
另一种方法是使用 traverseM
from 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)
。
所以如果你在 Stream[A]
上调用 traverseM
,并想返回 Option[Stream[(A, B)]]
,你应该给它传递一个函数 A => Option[Stream[(A, B)]]
– 这自然是 makeBs
,然后是构成 (A, B)
对的深度图。
后缀为M
的函数(filterM
、traverseM
、foldLeftM
等)通常在你想组合几个不同的上下文时非常有用,但是没有 monad 转换器的样板。
我正在处理一些嵌套的 Stream
s 并且想对它们使用 for comprehension 语法:
def handleNestedStream(as : Stream[A]) : Stream[(A, B)] = {
a <- as
b <- makeBs(a)
} yield (a, b)
但是,makeBs
函数 return 是一个 Option[Stream[B]]
。我希望 Option
自动展开。此外,如果 makeBs
失败,我希望整个函数 return 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)
唯一的变化是函数的类型。
我怎样才能完成这样的事情?来自 cats 的 StreamingT
或来自 scalaz 的 StreamT
可以帮助解决这个问题吗?
有些类型是灵活的。 makeBs
可以改为 return Stream[Option[B]]
而不是 Option[Stream[B]]
如果这样可以使事情更简单。
我需要使用 scala 标准库 Stream
类型。
让我们想象一下实现
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
将被评估为
Some(Stream((1,1), (3,333), (5,55555)))
另一种方法是使用 traverseM
from 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)
。
所以如果你在 Stream[A]
上调用 traverseM
,并想返回 Option[Stream[(A, B)]]
,你应该给它传递一个函数 A => Option[Stream[(A, B)]]
– 这自然是 makeBs
,然后是构成 (A, B)
对的深度图。
后缀为M
的函数(filterM
、traverseM
、foldLeftM
等)通常在你想组合几个不同的上下文时非常有用,但是没有 monad 转换器的样板。