I have a Seq[R]
and I wanna split this into a Tuple2[Seq[E], Seq[S]]
, while I was coding this I thought about the fact that I could use a custom Bifunctor
for a tuple of seqs and as exercise tried to code this:
import scalaz.Bifunctor
type MyType[E, S] = (Seq[E], Seq[S])
case class MyVali[E, S](tp: (Seq[E], Seq[S]))(implicit bifunctor: Bifunctor[MyType]) {
def bimap[C, D](f: (E) => C, g: (S) => D): (Seq[C], Seq[D]) =
bifunctor.bimap(tp)(f, g)
def leftMap[C](f: (E) => C): (Seq[C], Seq[S]) =
bifunctor.leftMap(tp)(f)
def rightMap[D](g: (S) => D): (Seq[E], Seq[D]) =
bifunctor.rightMap(tp)(g)
}
val myValBifunctorInstance = new Bifunctor[MyType] {
override def bimap[A, B, C, D](fab: (Seq[A], Seq[B]))(f: (A) => C, g: (B) => D): (Seq[C], Seq[D]) =
(fab._1.map(f), fab._2.map(g))
}
MyVali((Seq.empty[String], Seq.empty[Int]))(myValBifunctorInstance).bimap(a => a, b => b)
This works fine but for some reason obscure to me I had to declare a parametrized type alias to make all this compile, namely type MyType[E, S] = (Seq[E], Seq[S])
and I hardly understand why this works while this doesn't:
def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] {
override def bimap[A, B, C, D](fab: (A, B))(f: (A) => C, g: (B) => D): (C, D) = ???
}
[error] ... (Seq[E], Seq[S]) takes no type parameters, expected: two
[error] def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] {
Is the compiler creating a 2-type suspension (like a nested lambda type maybe?) when such a type alias is defined?
The
Tuple2[...]
in theBifunctor
above doesn't have two type parameters anymore because theE
andS
are filled in.Eg
myValBimap[Int, String]
tries to create aBifunctor[(Seq[Int], Seq[String])]
and the type(Seq[Int], Seq[String])
clearly has no two type parameters.You could write
Bifunctor[({ type λ[α, β] = (Seq[α], Seq[β])})#λ]
orBifunctor[λ[(α, β) => (Seq[α], Seq[β])]]
using the kind projector plugin.You need an implicit function with a type parameter if you need an additional type, maybe something like :
A simpler example is the
Functor
for disjunction /\/
which uses a type parameter for the left side :About your original problem: It might be possible to map your
R
toE \/ S
and useseparate
: