2013-03-03 24 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 
} 
相关问题