2014-10-06 71 views
2

我發現自己想要寫這篇文章:你如何讓一個班flatMappable?

def allAsAndFs(node: Node): PairOfSeqs[Action, Factor] = 
    node.regularNames.flatMap { name => regularAsAndFs(name) } ++ 
    node.specialNames.flatMap { name => specialAsAndFs(name) } 

其中:

def regularNames: Seq[String] 
def specialNames: Seq[String] 

def regularAsAndFs(name: String): PairOfSeqs[Action, Factor] 
def specialAsAndFs(name: String): PairOfSeqs[Action, Factor] 

和:

class PairOfSeqs[A, B](as: Seq[A], bs: Seq[B]) { 
    def ++(that: PairOfSeqs[A, B]): PairOfSeqs[A, B] = 
    PairOfSeqs(as ++ that.as, bs ++ that.bs) 
    . . . 
} 

什麼我需要做的,使flatMap聚結PairsOfSeqs通過 調用適當的++方法?

看起來像PairOfSeqs應該延伸GenTraversableOnce,但 GenTraversableOnce有一個相當驚人的47抽象方法來覆蓋。

什麼是地道的,Scalastic的方式來做到這一點?

回答

3

您正在使用flatMap的某種非標準想法。正常的類型簽名是

class C[A] { 
    def flatMap[B](f: A => C[B]): C[B] = ??? 
} 

但是你想要的(一個類似於 - 這不會編譯):

def foo[D <: { def ++(d: D): D }](f: A => D): D 

這更像fold超過flatMap

一種可能性是使PairOfSeqs成爲一個完整的集合。這將是艱難的,因爲這些類型確實不是很好排列,並且因爲擴展集合很困難。 (因爲即使努力是很大的回報是巨大的,如果你真的需要它的回報/努力比例可以是很好的。)

也許最好的可能性是隻是有一個擴展方法上Seq

case class PairOfSeqs[A, B](as: Seq[A], bs: Seq[B]) { 
    def ++(that: PairOfSeqs[A, B]): PairOfSeqs[A,B] = 
    PairOfSeqs(as ++ that.as, bs ++ that.bs) 
} 

implicit class SeqCanPairMap[A](val underlying: Seq[A]) extends AnyVal { 
    def flatPair[B,C](f: A => PairOfSeqs[B,C]): PairOfSeqs[B,C] = { 
    val ps = underlying.map(f) 
    PairOfSeqs(ps.map(_.as).fold(Seq[B]())(_ ++ _), ps.map(_.bs).fold(Seq[C]())(_ ++ _)) 
    } 
} 

Seq("fish", "fowl").flatPair(s => new PairOfSeqs(s.map(_.toChar), s.map(_.toInt))) 

有各種各樣的其他選項(例如定義一個更傳統的flatMapPairOfSeqs,並從正規seqs到PairOfSeqs轉換一個空的第二個插槽),但是這可能涉及您的使用情況不夠好。

最後,要創建一個類flatMappable一般來說,您所要做的就是定義flatMap。特別是,理解可以使用它。 (但是你也需要一個map,否則它對於理解不會有用。)

+0

我認爲向'PairOfSeqs'添加一個'flatMap'方法是行不通的,因爲Seq.flatMap'實際上得到了調用。 'Seq.flatMap'可以正確合併(「拼合」)'List','Option's,'Set's和其他東西。我想知道如何使它正確地合併「PairsOfSeqs」。我是否誤解了有關'flatMap'的一些基礎知識? (我仍在消化'SeqPairCanMap' ...) – 2014-10-06 17:57:32

+0

@BenKovitz - 'flatMap'實際上調用了從隱式CanBuildFrom中獲取的構建器。但是我想你要問的是,當你使用'flatMap'時,你是否可以從'Seq'到'PairOfSeqs'進行_implicit_轉換。在那裏,答案是否定的。 – 2014-10-06 18:02:43

+0

好的,現在我想我看到了我的困惑,這很好的解釋了答案頂部的類型簽名。我忘記了Seq.flatMap返回一個Seq,Set.flatMap返回一個Set,等等,不一定具有相同的類型參數。我在想'flatMap(f)'會返回一個與'f'返回的類型相同的值(我猜這是正常使用的)。謝謝! – 2014-10-06 18:05:42

相關問題