2016-02-29 61 views
3

我有以下問題:結合清單,期貨與期權在-理解 - scalaz

val sth: Future[Seq[T, S]] = for { 
    x <- whatever: Future[List[T]] 
    y <- x: List[T] 
    z <- f(y): Future[Option[S]] 
    n <- z: Option[S] 
} yield y: T -> n: S 

我希望讓這段代碼的工作(我猜每個人都明白這個想法,因爲我已經添加類型)。

通過「上班」我的意思是說,我希望留在理解結構中,並最終實現預期的類型。我知道有「醜陋」的方式來做到這一點,但我想學習如何做到這一點純粹:)

當我讀互聯網時,我已經得出結論,我的問題可能由monad變壓器解決& scalaz 。不幸的是,我找不到一個例子來幫助我更好地瞭解我應該如何繼續。

目前我已經嘗試了scalaz和Eff monad庫,但我想我仍然不明白它是如何工作的,因爲我無法解決我的問題。

我將不勝感激任何幫助。

編輯:這應該是序列的未來,還就「什麼」我把它作爲函數的參數,對不起,誤導您

回答

1

你可以做這樣的事情,你需要使用scalaz ListT monad transformer什麼

object Test { 
    import scalaz._ 
    import ListT._ 
    type T = String 
    type S = Int 
    val whatever: Future[List[T]] = ??? // you get this somewhere 
    def f(y: T): Future[Option[S]] = ??? // function that returns future of option 

    val sth: Future[List[(T, S)]] = (for { 
    y <- listT(whatever) 
    // you cannot mix list and option, but you can convert the option to a list of 1 item 
    n <- listT(f(y).map(_.toList)) 
    } yield y -> n).run 
} 

NB:既然你開始一個未來,你不能返回序列[(T,S),你只能有前途。如果您想阻止並獲得結果,您必須調用Await.result。

+0

謝謝!這非常有幫助,而且我正在尋找!需要說明的是,當我在T中使用任何類型的T(選項/列表/等)來理解時,我將不得不只使用它的一種類型來工作? – fr3ak

+0

是的,就好像你將所有東西都嵌入到了外部單子(在這種情況下的未來)中,「內部」單子仍然必須是相同的,就好像它們都是列表/選項/等。 –

1

for理解的問題是,它不是某種神奇的一元「解包」的,它只是一個mapflatMapfilter序列。

如您所知,mapflatMap僅對「內部」類型進行操作,使「外部」類型的monad保持不變。這意味着你不能這樣做:

for { 
    x <- whatever: Future[List[T]] 
    y <- x: List[T] 
} yield y 

裏面單for。相反,你可以這樣做:

for (x <- whatever: Future[List[T]]) 
    yield for (y <- x: List[T]) yield y 

這看起來有點醜。

返回到你的情況,我很容易編寫整個改造明確使用mapflatMap,因爲它給你更大的可視性和控制:

whatever.flatMap { 
    x: List[T] => 
    Future.sequence(x.map { 
     y: T => f(y).map(y -> _) 
    }).map(_.collect { 
     case (y, Some(n)) => y -> n 
    }) 
} 

此外,@trustnoone提到的,你無法擺脫的Future沒有明確呼籲Await