2013-03-03 79 views
1

比方說,我們有一個具有協變和逆變類型參數的類:如何爲具有協變/逆變類型參數的類定義flatMap?

sealed trait Pipe[-I,+O,+R] 
// case subclasses 

而且我們有這個類的實例定義一元操作:

object Pipe { 
    def flatMap[I,O,Ri,R](p: Pipe[I,O,Ri], f: Ri => Pipe[I,O,R]): Pipe[I,O,R] = 
     ... 
} 

爲了能夠使用for -comprehension,我們需要flatMap是性狀自身的方法:

sealed trait Pipe[-I,+O,+R] { 
    def flatMap[I,O,Ri,R](f: Ri => Pipe[I,O,R]): Pipe[I,O,R] = 
     Pipe.flatMap(this, f); 
} 

然而,這並不ñ OT編譯,它失敗

逆變型I發生協變位置中的值f(R) => Pipe[I,O,R1]類型。

(對於協變型參數發生以及類似的錯誤。)

我理解的限制,以及爲什麼出現問題。但是有沒有一些解決方法,如何使用Pipes.flatMap與上述相同的語義在特徵上定義flatMap?也許使用一些隱式轉換和/或中間構建器類?

回答

4

最簡單,

implicit def pipeFlatMap[I, O, A](pipe: Pipe[I, O, A]) = new { 
    def flatMap[B](f: A => Pipe[I, O, B]) = Pipe.flatMap(pipe, f) 
} 

如果您Pipe許可實施point,即def point[I, O, A](a: A): Pipe[I, O, A],然後執行一個完整的scalaz.Monad類型類可能是有用的,因爲Scalaz的implicits會給你免費flatMap和其他許多單子操作:

implicit def pipeMonad[I, O] = new Monad[({type λ[α]=Pipe[I, O, α]})#λ] { 
    // TODO implement point and bind 
} 
相關問題