2

Scala 2.10.2 を使用しています。

関数が必要です

def extractEither(m: M[(Key, Either[TLeft, TRight])])
: Either[TLeft, M[(Key, TRight)]]

whereMは、Seq、List、Map、またはその他のものにすることができ、戻り値の型は引き続き適切です。

私はテストのために以下を使用しています:

val map = Map(1 -> Left("foo"), 2 -> Right('bar), 3 -> Right('baz))

私の現在の試みは次のとおりです。

試み #1

def extractEither[
  Key, TLeft, TRight, M[_] <: TraversableOnce[_]
]
(monad: M[(Key, Either[TLeft, TRight])])
(implicit cbf: CanBuildFrom[
M[(Key, Either[TLeft, TRight])],
  (Key, TRight),
  M[(Key, TRight)]
]): Either[TLeft, M[(Key, TRight)]] = {
  val builder = cbf(monad)
  builder.sizeHint(monad.size)
  (monad: GenTraversableOnce[_]).foreach { x =>
    val (key, either) = x.asInstanceOf[(Key, Either[TLeft, TRight])]
    either.fold(
      leftVal => return Left(leftVal),
      rightVal => builder += ((key, rightVal))
    )
  }
  Right(builder.result())
}

これは次の場合に失敗します。

scala> extractEither(map)
<console>:20: error: no type parameters for method extractEither: (monad: M[(Key, Either[TLeft,TRight])])(implicit cbf: scala.collection.generic.CanBuildFrom[M[(Key, Either[TLeft,TRight])],(Key, TRight),M[(Key, TRight)]])Either[TLeft,M[(Key, TRight)]] exist so that it can be applied to arguments (scala.collection.immutable.Map[Int,Product with Serializable with scala.util.Either[String,Symbol]])
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : scala.collection.immutable.Map[Int,Product with Serializable with scala.util.Either[String,Symbol]]
 required: ?M
              extractEither(map)
              ^
<console>:20: error: type mismatch;
 found   : scala.collection.immutable.Map[Int,Product with Serializable with scala.util.Either[String,Symbol]]
 required: M[(Key, Either[TLeft,TRight])]
              extractEither(map)
                            ^
<console>:20: error: Cannot construct a collection of type M[(Key, TRight)] with elements of type (Key, TRight) based on a collection of type M[(Key, Either[TLeft,TRight])].
              extractEither(map)
                           ^

試み #2

これは、可変または不変のマップに制限されています。

def extractEither[
  Key, TLeft, TRight, M <: collection.Map[Key, Either[TLeft, TRight]]
](map: M): Either[TLeft, M] = {
  Right[TLeft, M](map.map { case (key, either) =>
    either.fold(
      leftVal => return Left(leftVal),
      rightVal => key -> rightVal
    )
  }.asInstanceOf[M])
}

これは次の場合に失敗します。

scala> extractEither(map)
<console>:20: error: inferred type arguments [Nothing,Nothing,Nothing,scala.collection.immutable.Map[Int,Product with Serializable with scala.util.Either[String,Symbol]]] do not conform to method extractEither's type parameter bounds [Key,TLeft,TRight,M <: scala.collection.Map[Key,Either[TLeft,TRight]]]
              extractEither(map)
              ^
<console>:20: error: type mismatch;
 found   : scala.collection.immutable.Map[Int,Product with Serializable with scala.util.Either[String,Symbol]]
 required: M
              extractEither(map)
                            ^

実用的な非一般的なソリューション

  def extractEither[
    Key, TLeft, TRight
  ](map: Map[Key, Either[TLeft, TRight]]): Either[TLeft, Map[Key, TRight]] = {
    Right(map.map { case (key, either) =>
      either.fold(
        leftVal => return Left(leftVal),
        rightVal => key -> rightVal
      )
    })
  }

しかし、これはまったく一般的ではありません:|

これを適切に書く方法について誰かが光を当てることができますか?

4

1 に答える 1