2016-07-25 80 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

第一次看起來好像你可以使用泛型作爲解決方案或通過繼承來解決你的問題。

相關問題