加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – ADT的类型类实例的通用派生

发布时间:2020-12-16 18:31:43 所属栏目:安全 来源:网络整理
导读:假设我有一个ADT并输入类Foo,如下所示: sealed trait Acase class A1() extends Acase class A2() extends Acase class A3() extends Atrait Foo[X] { def foo(x: X): String; }object Foo { implicit val a1foo = new Foo[A1] { def foo(a1: A1) = "A1" }
假设我有一个ADT并输入类Foo,如下所示:

sealed trait A
case class A1() extends A
case class A2() extends A
case class A3() extends A

trait Foo[X] { def foo(x: X): String; }
object Foo {
  implicit val a1foo = new Foo[A1] { def foo(a1: A1) = "A1" }
  implicit val a2foo = new Foo[A2] { def foo(a2: A2) = "A2" }
  implicit val a3foo = new Foo[A3] { def foo(a3: A3) = "A3" }
}

现在我可以像这样写Foo [A]:

implicit val afoo = new Foo[A] {
  def foo(a: A) = a match {
    case a1 : A1 => a1foo.foo(a1)
    case a2 : A2 => a2foo.foo(a2)
    case a3 : A3 => a3foo.foo(a3)
  }
}

不幸的是,这段代码太过于热衷.是否有可能摆脱所有样板并自动导出Foo [A](可能是无形的)?

解决方法

隐藏的这个afoo不仅在其他三个存在时无用,而且甚至很糟糕,因为它会因新的A {}值上的MatchError而失败.

当你有一个涵盖所有类型A的可能(有效)值并且afoo没有添加任何东西的含义时,我不明白为什么你需要这样的Foo [A]实例.

我可以想象,如果你有一个功能

def foo(a: A)(implicit f: Foo[A]): String = f.foo(a)

然后,当然,a1foo,a2foo或a3foo都不适合. afoo将,所以foo(A1())将编译并正常工作,但foo(new A {})也将编译,并因MatchError而失败.顺便说一句,如果代码中存在调用foo(new A {}),它将编译时会显示非详尽匹配的警告,但如果不是,则会以静默方式编译.

所以解决这个问题的方法是修改foo,采用更精确的类型:

def foo[X <: A](a: X)(implicit f: Foo[X]): String = f.foo(a)

现在foo(A1())将编译并选择a1foo(与A2和A3相同),而foo(new A {})只是不会编译(因为它不应该).

更新

如果您仍希望将Foo [A]的实例作为默认情况,则可以像这样更改代码:

object Foo extends Foo_1 {

  implicit val a1foo: Foo[A1] = ...
  implicit val a2foo: Foo[A2] = ...
  implicit val a3foo: Foo[A3] = ...
}

trait Foo_1 {
  // this implicit has a lower priority:
  implicit val afoo: Foo[A] = new Foo[A] { def foo(a: A) = "A" }
}

现在foo(new A {})或foo(A2():A)将编译并返回“A”.

附:顺便说一句,写出明确的implicits类型是recommended.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读