2013-03-03 3 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 происходит в ковариантной позиции в типе (R) => Pipe[I,O,R1] значения f.

(Подобная ошибка возникает для параметров ковариант- типа, а также.)

Я понимаю, ограничение и поэтому возникает проблема. Но есть ли способ обхода, как определить flatMap по признаку, используя Pipes.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 класса типов может быть полезным, так как implicits Scalaz дал бы вам flatMap и многие другие монадических операции бесплатно:

implicit def pipeMonad[I, O] = new Monad[({type λ[α]=Pipe[I, O, α]})#λ] { 
    // TODO implement point and bind 
} 
Смежные вопросы