2016-05-19 17 views
1

現在、型クラスを実装するいくつかのクラスをプログラミングしています。私はこの目的のために猫を使用します。この設定では、クラスA[T]B[T] <: A[T]があります。 A[T]はモナドなので、右のライブラリをインポートするときに、私はスカラ型クラスと継承でうまく動作しません

val x: A[Int] = ??? 
x.flatMap(_) 

を書くことができますが、ScalaはflatMap演算子を見つけることができませんので、私は

val x: B[Int] = ??? 
b.flatMap(_) 

を書き込むことはできません。 代わりに、これを動作させるには

val x: B[Int] = ??? 
(b: A[Int]).flatMap(_) 

と書かなければなりません。サブクラスがスーパークラスのメソッドを継承すると思うので、これは厄介です。

完全性のために、問題を示す依存関係のない最小限の例を追加します。ここでは、Filterableはtypecassであり、Sによって実装されています。 q.opが見つからないので

object StackOverflowTest { 
    class S[+T] 

    class Q[+T] extends S[T] 

    trait Filterable[F[+_]] { 
    def filter[A](x: F[A]): F[A] 
    } 

    implicit class FilterOps[F[+_], A](y: F[A])(implicit ev: Filterable[F]) { 
    def filter: F[A] = ev.filter(y) 
    } 

    implicit object SIsFilterable extends Filterable[S] { 
    def filter[A](x: S[A]): S[A] = x 
    } 

    //def failing = { 
    // val q = new Q[Int]() 
    // val r = q.filter 
    //} 

    def working = { 
    val q = new Q[Int]() 
    val r = (q: S[Int]).filter 
    } 
} 

failing定義は、コンパイルされません。一方、workingは、最初にSにキャストすることでこの問題を緩和します。私のライブラリーのユーザーのために、failingの例を動作させるにはどうすればよいですか?あなたが親の型にキャストしてそのメソッドを使用できるようにすることは非常に不自然に感じます。 (new Q[Int]()).filterタイプS[Int]なくQ[Int]のものでなければならないので、私はFilterable[Q]を実装する第二の暗黙的なオブジェクトを定義することができないこと

注、。

+0

同様の問題は、 '' Option'対Some'です。これは、猫が 'Xor'、' Validated'などのスマートなコンストラクタを提供する理由です。例えば 'Validated.Valid [Int]'ではなく 'Validated [Nothing、Int]'で終わるようにします。おそらく、Qと同様の戦略に従うことは可能でしょうか? –

+0

@PeterNeyens:残念ながら、Qにはユーザに公開したいいくつかの追加機能がありますので、これは不可能です。 –

答えて

1

はとSIsFilterableを交換してみてください:

implicit def sOrSubtypeIsFilterable [T[+_] <: S[_]] = new Filterable[T] { 
    def filter[A](x: T[A]): T[A] = x 
} 
+0

'filter'の戻り値の型は' S [A] 'でなければなりません。これが猫と一緒に働くのかなと思います。これを暗黙的に追加すると、あいまいな暗黙の定義に問題が生じる可能性があります。 –

+0

なぜ返品は 'S [A]'であるべきですか?フィルタリングされた 'Q [...]'が依然として 'Q [...]'であるようにはしませんか? –

+0

私の使用例で 'filter'は少し複雑で、' S [A] 'だけを返すことができます –

関連する問題