gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 21:35:56 27 4
gpt4 key购买 nike

假设我有一个 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]自动(也许与 shapeless )?

最佳答案

这个afoo隐含在其他三个存在时不仅无用,而且甚至很糟糕,因为它会失败并返回 MatchErrornew A {}值(value)。

我不明白你为什么需要 Foo[A] 这样的实例当您有涵盖 A 类型的所有可能(有效)值的隐式时和 afoo不添加任何东西。

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

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

那么,当然, a1foo , a2fooa3foo会适合。 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 (与 A2A3 相同),而 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" .

附言顺便说一下,它是 recommended编写显式类型的隐式。

关于scala - ADT 的类型类实例的通用派生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38168044/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com