使用选项中包含的Streams

时间:2015-11-07 15:22:56

标签: scala scalaz monad-transformers scala-cats

我正在使用一些嵌套的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类型。

2 个答案:

答案 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应该包含TraverseBind的实例,G应该有一个实例Applicative)。在这种情况下,FStreamGOption,签名中的B(A, B)

因此,如果您在traverseM上致电Stream[A],并希望返回Option[Stream[(A, B)]],则应将其传递给A => Option[Stream[(A, B)]]函数 - 这自然是makeBs ,然后是一个使(A, B)对成对的深度图。

带有后缀MfilterMtraverseMfoldLeftM等)的功能在您想要组合多个不同的上下文时通常非常有用,但没有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)))