如何在 Scala 中使用编码器类型类处理 Option
How to handle Option with an encoder typeclass in scala
我有一个经典的 Encoder
类型类。
trait Encoder[A] {
def encode(a: A): String
}
我有两个问题
问题一:分歧从何而来:
[error] … diverging implicit expansion for type sbopt.Test.Encoder[None.type]
[error] starting with value stringEncoder in object Test
[error] show(None)
implicit val stringEncoder = new Encoder[String] {
override def encode(a: String): String = a
}
implicit def optionEncoder[A: Encoder]: Encoder[Option[A]] =
(a: Option[A]) => {
val encoderA = implicitly[Encoder[A]]
a.fold("")(encoderA.encode)
}
implicit def someEncoder[A: Encoder]: Encoder[Some[A]] =
(a: Some[A]) => {
val encoderA = implicitly[Encoder[A]]
encoderA.encode(a.get)
}
implicit def noneEncoder[A: Encoder]: Encoder[None.type] =
(_: None.type) => ""
def show[A: Encoder](a: A) = println(implicitly[Encoder[A]].encode(a))
show(None)
问题2:我在circe看到Encoder不是逆变的。有什么优点和缺点?
trait Encoder[-A] {
def encode(a: A): String
}
implicit val stringEncoder: Encoder[String] = (a: String) => a
implicit def optionEncoder[A: Encoder]: Encoder[Option[A]] =
(a: Option[A]) => {
val encoderA = implicitly[Encoder[A]]
a.fold("")(encoderA.encode)
}
def show[A: Encoder](a: A) = println(implicitly[Encoder[A]].encode(a))
show(Option("value"))
show(Some("value"))
show(None)
关于 1.
你对noneEncoder
的定义不好。你有一个额外的上下文绑定(甚至额外的类型参数)。
有
implicit def noneEncoder/*[A: Encoder]*/: Encoder[None.type] =
(_: None.type) => ""
它编译:
show[Option[String]](None)
show[None.type](None)
show(None)
您对 noneEncoder
的原始定义意味着您有一个 Encoder
的实例用于 None.type
,前提是您有一个用于某些 A
的实例(不受约束,即推断)。如果你有唯一的隐式(或至少只有 higher-priority 隐式),通常这会起作用。例如,如果只有 stringEncoder
和原始 noneEncoder
,那么 show[None.type](None)
和 show(None)
将编译。
关于 2.
PROS. 逆变 Encoder
trait Encoder[-A] {
def encode(a: A): String
}
你可以去掉someEncoder
和noneEncoder
,optionEncoder
就够了
show(Some("a"))
show[Option[String]](Some("a"))
show[Option[String]](None)
show[None.type](None)
show(None)
CONS. 有些人认为逆变类型 类 行为违反直觉:
https://github.com/scala/bug/issues/2509
https://groups.google.com/g/scala-language/c/ZE83TvSWpT4/m/YiwJJLZRmlcJ
可能也相关:In scala 2.13, how to use implicitly[value singleton type]?
我有一个经典的 Encoder
类型类。
trait Encoder[A] {
def encode(a: A): String
}
我有两个问题
问题一:分歧从何而来:
[error] … diverging implicit expansion for type sbopt.Test.Encoder[None.type]
[error] starting with value stringEncoder in object Test
[error] show(None)
implicit val stringEncoder = new Encoder[String] {
override def encode(a: String): String = a
}
implicit def optionEncoder[A: Encoder]: Encoder[Option[A]] =
(a: Option[A]) => {
val encoderA = implicitly[Encoder[A]]
a.fold("")(encoderA.encode)
}
implicit def someEncoder[A: Encoder]: Encoder[Some[A]] =
(a: Some[A]) => {
val encoderA = implicitly[Encoder[A]]
encoderA.encode(a.get)
}
implicit def noneEncoder[A: Encoder]: Encoder[None.type] =
(_: None.type) => ""
def show[A: Encoder](a: A) = println(implicitly[Encoder[A]].encode(a))
show(None)
问题2:我在circe看到Encoder不是逆变的。有什么优点和缺点?
trait Encoder[-A] {
def encode(a: A): String
}
implicit val stringEncoder: Encoder[String] = (a: String) => a
implicit def optionEncoder[A: Encoder]: Encoder[Option[A]] =
(a: Option[A]) => {
val encoderA = implicitly[Encoder[A]]
a.fold("")(encoderA.encode)
}
def show[A: Encoder](a: A) = println(implicitly[Encoder[A]].encode(a))
show(Option("value"))
show(Some("value"))
show(None)
关于 1.
你对noneEncoder
的定义不好。你有一个额外的上下文绑定(甚至额外的类型参数)。
有
implicit def noneEncoder/*[A: Encoder]*/: Encoder[None.type] =
(_: None.type) => ""
它编译:
show[Option[String]](None)
show[None.type](None)
show(None)
您对 noneEncoder
的原始定义意味着您有一个 Encoder
的实例用于 None.type
,前提是您有一个用于某些 A
的实例(不受约束,即推断)。如果你有唯一的隐式(或至少只有 higher-priority 隐式),通常这会起作用。例如,如果只有 stringEncoder
和原始 noneEncoder
,那么 show[None.type](None)
和 show(None)
将编译。
关于 2.
PROS. 逆变 Encoder
trait Encoder[-A] {
def encode(a: A): String
}
你可以去掉someEncoder
和noneEncoder
,optionEncoder
就够了
show(Some("a"))
show[Option[String]](Some("a"))
show[Option[String]](None)
show[None.type](None)
show(None)
CONS. 有些人认为逆变类型 类 行为违反直觉:
https://github.com/scala/bug/issues/2509
https://groups.google.com/g/scala-language/c/ZE83TvSWpT4/m/YiwJJLZRmlcJ
可能也相关:In scala 2.13, how to use implicitly[value singleton type]?