私はscalazライブラリを使用してscalaのモナドで何かをしようとしていますが、サブタイピングでうまく機能させるのに問題があります。
私は自分のモナドを定義することから始めました。簡単にするために、それをアイデンティティモナドとします。
import scalaz._
import Scalaz._
class Id[+A] (val value : A) { }
implicit object IdMonad extends Monad[Id] {
override def pure[A](a : => A) = new Id(a)
override def bind[A, B](a : Id[A], f : A => Id[B]) = f(a.value)
}
次に、いくつかの追加機能で拡張しました。
class ExtendedId[A] (value : A, val printer : A => String) extends Id[A](value) { }
この追加機能により、ExtendedId
はもはやモナドではありません。
ここで、タイプのオブジェクトを:ExtendedId[A]
として使用したいと思います。Id[A]
def increment1(v : ExtendedId[Int]) : Id[Int] = {
for(v <- v) yield v + 1;
// ^
// error: could not find implicit value for parameter t: scalaz.Functor[test.package.ExtendedId]
}
ExtendedId
はモナドではないので、出力として取得できる最高のものはであると理解していることに注意してください。それで問題ありませんId[Int]
。しかし残念ながら、そのコードはまだコンパイルされません。
ただし、これは次のことを行います。
def asId[A](a : ExtendedId[A]) : Id[A] = a
def increment2(v : ExtendedId[Int]) {
for(v <- asId(v)) yield v + 1;
}
ここで、asId
関数は引数をfromからにアップキャストするだけExtendedId[A]
ですId[A]
。完全に冗長なはずですが、そうではありません。
なぜこうなった?Id[A]
を含むオブジェクトへの暗黙の変換が存在し、からへmap
の些細な暗黙の変換が明らかに存在します。では、なぜコンパイラーはそれらを組み合わせることができないのですか?ExtendedId[A]
Id[A]