2015-11-07 66 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等)的功能通常是非常有用的,當你想幾處不同的組合,但沒有單子變壓器的樣板。