Псевдоним параметризованного типа для бифункторов

У меня есть Seq[R], и я хочу разделить это на Tuple2[Seq[E], Seq[S]], пока я кодировал это, я подумал о том, что могу использовать пользовательский Bifunctor для кортежа последовательностей, и в качестве упражнения попытался закодировать это:

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-типа (например, вложенный лямбда-тип, может быть?), когда такой псевдоним типа определен?


person Ende Neu    schedule 14.06.2016    source источник


Ответы (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[β])})#λ] or
  • Bifunctor[λ[(α, β) => (Seq[α], Seq[β])]] с помощью плагина Kind Projector.

Вам нужна неявная функция с параметром типа, если вам нужен дополнительный тип, может быть, что-то вроде:

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))
person Peter Neyens    schedule 14.06.2016