2016-07-25 14 views
1

は、私はこのようなADT持っていると仮定します。この場合、タイプクラスを使用しますか?

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

今私はAFooための2つの異なる実装を提供する必要があります。

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を持っているにもあるとします。だから私はそのようなことを書いています:

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)が1つしかありません。ここでは、型クラスを使用する大きな利点はありません。引数の1つが汎用である場合は、型クラスを検討することにします。コメントで示唆したように

は、1は折り

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

最初に、ジェネリックをソリューションとして使用したり、継承に関する問題を解決したりできるようです。

関連する問題