Почему у кошек есть две группы параметров Bifunctor [F [_, _]]. Bimap function? - PullRequest
0 голосов
/ 26 сентября 2019

Я наткнулся на эту проблему при попытке реализовать класс типа Bifunctior для карт (Bifunctor[Map[_, _]]).

Bifunctor определяется следующим образом для кошек:

/**
   * The quintessential method of the Bifunctor trait, it applies a
   * function to each "side" of the bifunctor.
   *
   * Example:
   * {{{
   * scala> import cats.implicits._
   *
   * scala> val x: (List[String], Int) = (List("foo", "bar"), 3)
   * scala> x.bimap(_.headOption, _.toLong + 1)
   * res0: (Option[String], Long) = (Some(foo),4)
   * }}}
   */
  def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D]

Как отмечается в комментарии, эта функция может быть вызвана с использованием двух функций (в одной группе параметров) в качестве входных данных, например: x.bimap(_.headOption, _.toLong + 1).Это говорит мне о том, что это явно не вызываемая функция bimap, так как эта имеет две группы параметров ((fab: F[A, B])(f: A => C, g: B => D)).Мне было интересно, есть ли какое-то неявное преобразование типов, которое я не знаю, что происходит здесь.Как это работает?Что мне нужно реализовать, чтобы получить класс типа Bifunctor для карт?

1 Ответ

5 голосов
/ 26 сентября 2019

Экземпляр класса типа Bifunctor для Map может быть определен следующим образом

implicit val mapBifunctor: Bifunctor[Map] = new Bifunctor[Map] {
  override def bimap[A, B, C, D](fab: Map[A, B])(f: A => C, g: B => D): Map[C, D] = 
    fab.map { case (k, v) => f(k) -> g(v) }
}

В x.bimap(_.headOption, _.toLong + 1) импликации разрешаются дважды:

  • во-первых, найден экземпляр Bifunctor[Tuple2] (import cats.instances.tuple._ или import cats.instances.all._ или import cats.implicits._),

  • во-вторых, разрешен метод расширения (import cats.syntax.bifunctor._ или import cats.syntax.all._ или import cats.implicits._)

Таким образом x.bimap(_.headOption, _.toLong + 1) преобразуется в

implicitly[Bifunctor[Tuple2]].bimap(x)(_.headOption, _.toLong + 1)

или

Bifunctor[Tuple2].bimap(x)(_.headOption, _.toLong + 1)

или

toBifunctorOps(x)(catsStdBitraverseForTuple2).bimap(_.headOption, _.toLong + 1)
...