类型 class 解析中的隐式类别
Implicit categories in type class resolution
我怀疑,
大多数人都知道 Show 示例来介绍类型 class。
我发现了这个博客 post https://scalac.io/typeclasses-in-scala/,当我偶然发现一些我不太理解的东西并希望有人能帮助澄清它时,我正在轻松地浏览它。
我理解博客中的所有内容 post 期待它谈论隐式类别时:
来自类型 class 具有语法和对象接口的完整定义
trait Show[A] {
def show(a: A): String
}
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
//needed only if we want to support notation: show(...)
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
//type class instances
implicit val intCanShow: Show[Int] =
int => s"int $int"
implicit val stringCanShow: Show[String] =
str => s"string $str"
}
我们收到以下评论:
We may encounter a need to redefine some default type class instances. With the implementation above, if all default instances were imported into scope we cannot achieve that. The compiler will have ambiguous implicits in scope and will report an error.
We may decide to move the show function and the ShowOps implicit class
to another object (let say ops) to allow users of this type class to
redefine the default instance behaviour (with Category 1 implicits,
more on categories of implicits). After such a modification, the Show
object looks like this:
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
object ops {
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
}
implicit val intCanShow: Show[Int] =
int => s"int $int"
implicit val stringCanShow: Show[String] =
str => s"string $str"
}
Usage does not change, but now the user of this type class may import only:
import show.Show
import show.Show.ops._
Default implicit instances are not brought as Category 1 implicits (although they are available as Category 2 implicits), so it’s possible to define our own implicit instance where we use such type class.
最后一条评论我没听懂?
Show[Int]
和 Show[String]
的隐式实例是在 Show
伴生对象中定义的,因此每当使用 Show
类型的值时,类型 class 实例将可用。但是,它们可以被用户覆盖。这使它们成为第 2 类隐式 - 它们来自 隐式范围 .
另一方面,通过直接导入进入范围的隐式是类别 1 隐式。它们来自 本地范围 并且不能被覆盖。因此,直接导入隐式与当场定义它们是一样的——两者都被认为是第 1 类。如果在本地范围内存在多个相同类型的第 1 类隐式值,编译器会报错。
文章说的是,将你的隐式实现放在伴随对象中,但将“机器”放在 ops
中。这样 class 类型的用户就可以只导入允许他们做的机器,例如42.show
,没有引入类型 class 实例作为类别 1 值。
然后我们的用户可以这样做:
import show.Show
import show.Show.ops._
// available from Show as category 2 implicit:
println(42.show) // "int 42"
以及:
import show.Show
import show.Show.ops._
// overriding category 2 implicit with our own category 1 implicit:
implicit val myOwnIntCanShow: Show[Int] = int => s"my own $int"
println(42.show) // prints "my own 42"
但是,如果我们没有 ops
对象,而只是将所有内容都放在 Show
对象中,那么每当我们的用户执行 import Show._
(并且他们需要,为了能够做到 42.show
) 他们将接收我们所有的隐式作为类别 1 值并且将无法覆盖它们:
import show.Show
// Assuming everything is in `Show` (no `ops`)...
import show.Show._
implicit val myOwnIntCanShow: Show[Int] = int => s"my own $int"
// this line doesn't compile because implicits were brought
// into scope as category 1 values (via import Show._)
println(42.show)
本教程的作者调用 higher-priority implicits(从本地范围)Category-1 implicits 和 lower-priority implicits(从隐式范围)2 类隐式。
Where does Scala look for implicits?
https://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html
我怀疑,
大多数人都知道 Show 示例来介绍类型 class。
我发现了这个博客 post https://scalac.io/typeclasses-in-scala/,当我偶然发现一些我不太理解的东西并希望有人能帮助澄清它时,我正在轻松地浏览它。
我理解博客中的所有内容 post 期待它谈论隐式类别时:
来自类型 class 具有语法和对象接口的完整定义
trait Show[A] {
def show(a: A): String
}
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
//needed only if we want to support notation: show(...)
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
//type class instances
implicit val intCanShow: Show[Int] =
int => s"int $int"
implicit val stringCanShow: Show[String] =
str => s"string $str"
}
我们收到以下评论:
We may encounter a need to redefine some default type class instances. With the implementation above, if all default instances were imported into scope we cannot achieve that. The compiler will have ambiguous implicits in scope and will report an error.
We may decide to move the show function and the ShowOps implicit class to another object (let say ops) to allow users of this type class to redefine the default instance behaviour (with Category 1 implicits, more on categories of implicits). After such a modification, the Show object looks like this:
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
object ops {
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
}
implicit val intCanShow: Show[Int] =
int => s"int $int"
implicit val stringCanShow: Show[String] =
str => s"string $str"
}
Usage does not change, but now the user of this type class may import only:
import show.Show
import show.Show.ops._
Default implicit instances are not brought as Category 1 implicits (although they are available as Category 2 implicits), so it’s possible to define our own implicit instance where we use such type class.
最后一条评论我没听懂?
Show[Int]
和 Show[String]
的隐式实例是在 Show
伴生对象中定义的,因此每当使用 Show
类型的值时,类型 class 实例将可用。但是,它们可以被用户覆盖。这使它们成为第 2 类隐式 - 它们来自 隐式范围 .
另一方面,通过直接导入进入范围的隐式是类别 1 隐式。它们来自 本地范围 并且不能被覆盖。因此,直接导入隐式与当场定义它们是一样的——两者都被认为是第 1 类。如果在本地范围内存在多个相同类型的第 1 类隐式值,编译器会报错。
文章说的是,将你的隐式实现放在伴随对象中,但将“机器”放在 ops
中。这样 class 类型的用户就可以只导入允许他们做的机器,例如42.show
,没有引入类型 class 实例作为类别 1 值。
然后我们的用户可以这样做:
import show.Show
import show.Show.ops._
// available from Show as category 2 implicit:
println(42.show) // "int 42"
以及:
import show.Show
import show.Show.ops._
// overriding category 2 implicit with our own category 1 implicit:
implicit val myOwnIntCanShow: Show[Int] = int => s"my own $int"
println(42.show) // prints "my own 42"
但是,如果我们没有 ops
对象,而只是将所有内容都放在 Show
对象中,那么每当我们的用户执行 import Show._
(并且他们需要,为了能够做到 42.show
) 他们将接收我们所有的隐式作为类别 1 值并且将无法覆盖它们:
import show.Show
// Assuming everything is in `Show` (no `ops`)...
import show.Show._
implicit val myOwnIntCanShow: Show[Int] = int => s"my own $int"
// this line doesn't compile because implicits were brought
// into scope as category 1 values (via import Show._)
println(42.show)
本教程的作者调用 higher-priority implicits(从本地范围)Category-1 implicits 和 lower-priority implicits(从隐式范围)2 类隐式。
Where does Scala look for implicits?
https://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html