【问题标题】:How to handle Option with an encoder typeclass in scala如何在 scala 中使用编码器类型类处理选项
【发布时间】:2021-01-09 15:23:30
【问题描述】:

我有一个经典的Encoder 类型类。

trait Encoder[A] {
  def encode(a: A): String
}

我有两个问题

问题1:分歧从何而来:

[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:我看到 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)

【问题讨论】:

  • 不需要 NoneSome 编码器。 Option 一个就足够了。
  • @LuisMiguelMejíaSuárez 这取决于您是否要显式指定show 的类型参数(或提供类型归属提示或使用智能构造函数.some.none[A])以及多少类型-您将继续前进的水平。

标签: scala typeclass implicit


【解决方案1】:

关于 1.

你对noneEncoder的定义不好。你有一个额外的上下文绑定(甚至是额外的类型参数)。

implicit def noneEncoder/*[A: Encoder]*/: Encoder[None.type] =
  (_: None.type) => ""

编译:

show[Option[String]](None)
show[None.type](None)
show(None)

您对noneEncoder 的原始定义意味着您拥有None.typeEncoder 实例,前提是您有一些A 的实例(不受限制,即被推断)。通常,如果您有唯一的隐式(或至少唯一的更高优先级的隐式),则此方法有效。例如,如果只有stringEncoder 和原始noneEncoder,那么show[None.type](None)show(None) 将编译。

关于 2.

优点。 带有逆变器Encoder

trait Encoder[-A] {
  def encode(a: A): String
}

你可以去掉someEncodernoneEncoderoptionEncoder就够了

show(Some("a"))
show[Option[String]](Some("a"))
show[Option[String]](None)
show[None.type](None)
show(None)

缺点。有些人认为逆变类型类的行为违反直觉:

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]?

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2012-03-31
  • 1970-01-01
  • 2016-12-24
  • 2021-04-01
  • 1970-01-01
  • 2020-08-18
  • 1970-01-01
  • 2015-04-03
相关资源
最近更新 更多