Как реализовать автоматическое преобразование из класса типов в синтаксис интерфейса (пример Cats) - PullRequest
1 голос
/ 11 июля 2019

Я работаю над книгой Scala с Cats , и мне интересно, как библиотека реализует некоторые функции, описанные в примере. В частности, речь идет об автоматической генерации неявного класса из существующего определения класса типа с использованием неявного преобразования.

Я имею в виду упражнение 1.4.6 в книге Scala с кошками . Для полноты я воспроизвел приведенный ниже код.

import cats.Show
import cats.instances.int._    
import cats.instances.string._
import cats.syntax.show._ 

final case class Cat(name: String, age: Int, color: String)

implicit val catShow = Show.show[Cat] { cat =>
  val name  = cat.name.show
  val age   = cat.age.show
  val color = cat.color.show
  s"$name is a $age year-old $color cat."
}

println(Cat("Garfield", 38, "ginger and black").show)

Я понимаю все об этом примере, кроме последней строки. Неявный catShow определяет только класс типа. Он не определяет, что в книге «1010 * Scala with Cats » называется «интерфейсный синтаксис». То есть он не определяет неявный класс, который необходим для работы последней строки.

Этот неявный класс будет выглядеть примерно так:

implicit class showCat(in: Cat) {
  def show: String = s"${in.name}, ${in.age}, ${in.color}"
}

Очевидно, я нигде не определил этот неявный класс, то есть он должен генерироваться автоматически. Я думаю, что он должен использовать некое неявное преобразование, которое преобразует из экземпляра Show [Cat] в неявный класс, который я создал выше.

Однако я не уверен, как написать это неявное преобразование класса, и мне было интересно, может ли кто-нибудь помочь мне, либо описав, как библиотека Cats реализует это, либо выписав код для реализации, которая сделает эту работу одинаково хорошо.

Для получения дополнительной информации, пожалуйста, обратитесь к книге Scala с кошками , которую можно бесплатно скачать здесь: https://books.underscore.io/scala-with-cats/scala-with-cats.html

1 Ответ

4 голосов
/ 11 июля 2019

Такой неявный класс может выглядеть как общий

implicit class ShowOps[A: Show](in: A) {
  def show: String = implicitly[Show[A]].show(in)
}

, а не как конкретный

implicit class showCat(in: Cat) {
  def show: String = s"${in.name}, ${in.age}, ${in.color}"
}

, поэтому для неявного преобразования не обязательно знать о Cat.

На самом деле с import cats.syntax.show._ вы импортируете что-то подобное.

https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/syntax/package.scala#L55

https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/syntax/show.scala

https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/Show.scala#L23-L34

...