在这种情况下你会使用类型 class 吗?

Would you use a type class in this case?

假设我有这样的 ADT:

sealed trait A extends Product with Serializable
object A {
  case class A1() extends A
  case class A2() extends A
  case class A3() extends A
  case class A4() extends A
}

假设我也有一个这样的 trait AFoo:

type Foo = ...
trait AFoo { def asFoo(a: A): Foo }

现在我需要为 AFoo 提供两种不同的实现。所以我正在写这样的东西:

abstract class AFooSupport extends AFoo {

  protected def asFoo1(a1: A1): Foo
  protected def asFoo2(a2: A2): Foo
  protected def asFoo3(a3: A3): Foo
  protected def asFoo4(a4: A4): Foo

  def asFoo(a: A) = a match {
    case a1: A1 => asFoo1(a1)
    case a2: A2 => asFoo2(a2)
    case a3: A3 => asFoo3(a3)
    case a4: A4 => asFoo4(a4)
  }
} 

class AFoo1 extends AFooSupport { 
  // implement asFoo1, asFoo2, asFoo3, asFoo4
}

class AFoo2 extends AFooSupport { 
  // implement asFoo1, asFoo2, asFoo3, asFoo4
}

这种方法可能会奏效,但我想知道是否有更好的方法。在这种情况下,您会使用 type class 吗?

乍一看,您似乎可以使用泛型作为解决方案或通过继承解决您的问题。

对于具有不同实现的具体 classes,只有一个函数 (A => Foo)。我在这里看不到使用类型 class 的巨大优势。当其中一个参数是泛型时,我会开始考虑类型 class。

正如评论中所建议的那样,可以将模式匹配提取到折叠中

def fold[F](a: A)(f1: A1 => F, ..., f4: A4 => F): F = a match {
    case a1: A1 => f1(a1)
    ...
}

并实现所需的功能:

def aFoo(a: A): Foo = fold(a)(afoo1, afoo2, afoo3, afoo4)
def afoo1(a: A1): Foo = ... 
...
def afoo4(a: A4): Foo = ...

def bFoo(a: A): Foo = fold(a)(bfoo1, bfoo2, bfoo3, bfoo4)
...
def bfoo4(a: A4): Foo = ...

但是您的 AFooSupport 已经是一种使用继承而不是组合实现的折叠。