2016-07-25 57 views
1

假设我有一个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

你确实需要'asFoo'的多个实现吗?对仅适用于单个ADT的操作使用类型类似乎很奇怪。如果你真的想抽象出匹配,那么折叠看起来更合理。 –

+0

我只需要一个'asFoo'的实现。将尝试'折叠',谢谢。 – Michael

回答

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已经是那种使用继承而不是组成实施了折。

+2

请注意,对于'fold',每个参数函数不需要将'A1'等作为参数 - 'A1'等没有成员,所以fold的参数为'(f1:=> F,f2:=> F,...)'。 –

-2

第一次看起来好像你可以使用泛型作为解决方案或通过继承来解决你的问题。

相关问题