3

mapメソッドを持つ型で機能する関数を実装しようとしていますflatMap。私はすでに のためにそれを作っていますが、これにはandが直接Traversable含まれていません。そこで、型クラスを使用して独自のインターフェイスを使用することにしました。FutureOption

trait CanMap[A, M[_]] {
  def map[B](l: M[A])(f: A => B): M[B]
  def flatMap[B](l: M[A])(f: A => M[B]): M[B]
}

私はすでにこれを実装しましたOption

  implicit def canmapopt[A] = new CanMap[A, Option] {
    def map[B](l: Option[A])(f: A => B): Option[B] = l.map(f)
    def flatMap[B](l: Option[A])(f: A => Option[B]): Option[B] = l.flatMap(f)
  }

これは非常にうまく機能します。の任意のサブタイプに対して実装したかったのでTraversable、オプションの実装に非常に近い実装を試みました。

  implicit def canmaptrav[A, B, T[B] <: Traversable[B]] = new CanMap[A, T] {
    def map[B](l: T[A])(f: A => B): T[B] = l.map(f)
    def flatMap[B](l: T[A])(f: A => T[B]): T[B] = l.flatMap(f)
  }

しかし、私はエラーが発生します:

  type mismatch;  found   : Traversable[B]  required: T[B]  Note: implicit method canmaptrav is not applicable here because it comes after the application point and it lacks an explicit result type

の戻り値の型l.map。特定の type ではなくl.map(f)a を返す理由がわかりません。だから私は明示的に適切なタイプの CanBuildFrom をコンテキストに入れようとしました:TraversableT[B]

  implicit def canmaptrav[A, B, T[B] <: Traversable[B]](implicit cbf: CanBuildFrom[T[A], B, T[B]]) = new CanMap[A, T] {
    def map[B](l: T[A])(f: A => B): T[B] = l.map(f)
    def flatMap[B](l: T[A])(f: A => T[B]): T[B] = l.flatMap(f)
  }

エラーが続く。

私がどこで間違ったのか分かりますか?明らかかもしれませんが、私が推測するジェネリック型シグネチャと混同しています。

更新: 解決策

まず第一に、回答が指摘したように、CanMapほとんどが Functor/Monad であるため、勇気があれば、scalazを使用してこれを実装できます。ただし、あなたが私のようで、それなしで試してみたい場合は、Kipton Barros の回答に基づく解決策を次に示します。

trait CanMap[A, B, M[_]] {
  def map(l: M[A])(f: A => B): M[B]
  def flatMap(l: M[A])(f: A => M[B]): M[B]
}

implicit def canmapopt[A, B] = new CanMap[A, B, Option] {
  def map(l: Option[A])(f: A => B): Option[B] = l.map(f)
  def flatMap(l: Option[A])(f: A => Option[B]): Option[B] = l.flatMap(f)
}

implicit def canmaptrav[A, B, M[+_]](implicit bf: CanBuildFrom[M[A], B, M[B]], ev: M[A] => TraversableLike[A, M[A]], eb: M[B] => TraversableLike[B, M[B]]) = new CanMap[A, B, M] {
  def map(l: M[A])(f: (A) => B): M[B] = l.map(f)
  def flatMap(l: M[A])(f: A => M[B]): M[B] = l.flatMap[B, M[B]] { (a: A) =>
    f(a)
  }
} 

秘訣は、M[A] => TraversableLike[A, M[A]]サブタイプを試行する代わりに暗黙の変換を使用することTraversableです。

4

3 に答える 3

2

最初に、失敗した 2 回の試行を試みましたが、あまり効果がありませんでした。それから私は単純化して、独自の CanMap 実装を行うことにしました。私はこれで終わった:

  def canmaptrav[A] = new CanMap[A, Traversable]{
    def map[B](l: Traversable[A])(f: A => B): Traversable[B]= l.map(f)
    def flatMap[B](l: Traversable[A])(f: A => Traversable[B]): Traversable[B] = l.flatMap(f)
  }

まさにCanMap[_,Option]. 探しているサブタイプが次のようなユースケース用であると仮定します。

canmaptrav[Int].map(List(1,2,3,4))(_ + 1)       //> res0: Traversable[Int] = List(2, 3, 4, 5)
canmaptrav[Int].map(Vector(1,2,3,4))(_ + 1)     //> res1: Traversable[Int] = Vector(2, 3, 4, 5)

ここで、res1 および res0 タイプを具体的なタイプ (List、Vector) にしたい場合、アプローチは実際にCanBuildFromfrom に依存する必要があります。

CanMapところで、これがほぼ Monad インターフェースであることはご存知ですよね?

于 2013-04-16T02:35:17.103 に答える
2

Scalazにはすでにこれらの型クラスが含まれており、 and と呼ばれMonadていFunctorます。簡単な例:

// map
def foo[F[_] : Functor](xs: F[Int]) = xs.map(_ + 1)

scala> foo(List(1,2,3))
res2: List[Int] = List(2, 3, 4)

// flatMap
def flatten[M[_] : Monad](xs: M[M[Int]]) = xs.flatMap(identity)

scala> flatten(List(List(1,2,3)))
res3: List[Int] = List(1, 2, 3)

編集

のファンクター インスタンスは次のFutureようになります。

implicit object FutureFunctor extends Functor[Future] {
  def map[A,B](fa: Future[A])(f: A => B) = fa.map(f)
}
于 2013-04-16T09:09:22.453 に答える