現在、型クラスを実装するいくつかのクラスをプログラミングしています。私はこの目的のために猫を使用します。この設定では、クラス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]
を実装する第二の暗黙的なオブジェクトを定義することができないこと
注、。
同様の問題は、 '' Option'対Some'です。これは、猫が 'Xor'、' Validated'などのスマートなコンストラクタを提供する理由です。例えば 'Validated.Valid [Int]'ではなく 'Validated [Nothing、Int]'で終わるようにします。おそらく、Qと同様の戦略に従うことは可能でしょうか? –
@PeterNeyens:残念ながら、Qにはユーザに公開したいいくつかの追加機能がありますので、これは不可能です。 –