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

时间:2016-07-25 15:47:27

标签: scala polymorphism typeclass

假设我有这样的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
}

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

2 个答案:

答案 0 :(得分:1)

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

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

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已经是使用继承而不是合成实现的折叠。

答案 1 :(得分:-2)

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