Параметризованный псевдоним типа для бифункторов
У меня есть Seq[R]
и я хочу разделить это на Tuple2[Seq[E], Seq[S]]
в то время как я кодировал это, я думал о том, что я мог бы использовать обычай Bifunctor
для кортежа seqs и в качестве упражнения попытался закодировать это:
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)
Это работает нормально, но по какой-то причине мне неясно, мне пришлось объявить параметризованный псевдоним типа, чтобы сделать все это компилировать, а именно type MyType[E, S] = (Seq[E], Seq[S])
и я не понимаю, почему это работает, а это не так:
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) = ???
}
[ошибка] ... (Seq[E], Seq[S]) не принимает параметров типа, ожидается: два
[ошибка] def myValBimap[E, S] = новый бифунктор [Tuple2[Seq[E], Seq[S]]] {
Создает ли компилятор подвеску 2-го типа (может быть, как вложенный лямбда-тип?), Когда такой псевдоним типа определен?
1 ответ
def myValBimap[E, S] = new Bifunctor[Tuple2[Seq[E], Seq[S]]] { ... }
Tuple2[...]
в Bifunctor
выше не имеет двух параметров типа больше, потому что E
а также S
заполнены.
Например myValBimap[Int, String]
пытается создать Bifunctor[(Seq[Int], Seq[String])]
и тип (Seq[Int], Seq[String])
явно не имеет двух параметров типа.
Вы могли бы написать
Bifunctor[({ type λ[α, β] = (Seq[α], Seq[β])})#λ]
или жеBifunctor[λ[(α, β) => (Seq[α], Seq[β])]]
используя добрый плагин проектора.
Вам нужна неявная функция с параметром типа, если вам нужен дополнительный тип, например что-то вроде:
implicit def myBimap[F[_]: Functor]: Bifunctor[λ[(α, β) => (F[α], F[β])]] = ???
Более простым примером является Functor
для дизъюнкции / \/
который использует параметр типа для левой стороны:
implicit def functorDisj[L]: Functor[L \/ ?] = ???
implicit def functorDisj[L]: Functor[({ type λ[α] = L \/ α })#λ] = ???
О вашей первоначальной проблеме: возможно, можно отобразить R
в E \/ S
и использовать separate
:
import scalaz._, Scalaz._
val integers = List.range(1,10)
val stringOrInts: List[String \/ Int] =
integers.map(i => if (i % 2 == 0) i.right else i.toString.left)
stringOrInts.separate
// (List[String], List[Int]) = (List(1, 3, 5, 7, 9),List(2, 4, 6, 8))