Maybe I'm missing something obvious, but I'm trying to clean up some boilerplate in a project that uses Scalaz 7, and I'm not finding one particular puzzle piece that seems pretty simple and possibly useful.
Suppose we have a bijection between two types:
case class Foo(x: Int)
case class Bar(i: Int)
import scalaz._, Scalaz._, BijectionT._
val fb: Foo <@> Bar = bijection[Id, Id, Foo, Bar](
foo => Bar(foo.x),
bar => Foo(bar.i)
)
Now suppose we find that we need a bijection between List[Foo]
and List[Bar]
. We can easily write an implicit class that provides this functionality (in fact we may as well make it work for any functor):
implicit class BijectionLifter[A, B](val bij: A <@> B) extends AnyVal {
def liftInto[F[_]: Functor]: F[A] <@> F[B] = bijection[Id, Id, F[A], F[B]](
_ map bij.to,
_ map bij.from
)
}
Note that this is a straightforward translation of bimap
from Haskell's Data.Bijection
. Scalaz's bijection also has a method named bimap
, but it has a much busier type and doesn't seem to do what I want in any obvious way.
Now we can just write the following:
fb.liftInto[List]
And we've got the bijection we need.
Am I missing some abstraction that would make it possible for me to write this more cleanly with the functions and instances already provided for bijections in Scalaz 7?