如何实现类型class到接口语法的自动转换(Cats示例)

How to implement automatic conversion from type class to interface syntax (Cats example)

我正在阅读 Scala with Cats 一书,我想知道该库如何实现示例中描述的某些功能。具体来说,它是关于使用隐式转换从现有类型 class 定义自动生成隐式 class。

我特别指的是 Scala with Cats 一书中的练习 1.4.6。为了完整起见,我复制了下面的代码。

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 隐式仅定义类型 class。它没有定义 Scala with Cats 一书中提到的 "interface syntax." 也就是说,它没有定义获取最后一个所需的隐式 class上班。

隐含的 class 看起来像这样:

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

显然,我没有在任何地方定义这个隐含的 class,这意味着它必须自动生成。我认为它必须使用某种隐式转换,将 Show[Cat] 实例转换为我在上面创建的隐式 class 。

但是,我不确定如何编写这个隐式 class 转换,并且想知道是否有人可以帮助我,要么通过描述 Cats 库如何实现它,要么通过为一个实现同样出色的工作。

有关其他上下文,请参阅此处免费提供的 Scala with Cats 一书:https://books.underscore.io/scala-with-cats/scala-with-cats.html

这种隐含的 class 可能看起来像通用的

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