"缺少参数类型"在重载flatMap时的for -reherehe

时间:2016-08-25 14:48:18

标签: scala functional-programming

我编写了自己的类似Either的monad类,名为Maybe,其中包含值或错误对象。我希望此类的对象与Future结合使用,以便将Maybe[Future[T], E]]转换为Future[Maybe[T, E]]。因此,我实施了两个flatMap方法:

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

sealed abstract class Maybe[+E, +V] {

  def map[W](f: V ⇒ W ): Maybe[E, W] = this match {
    case Value(v) ⇒ Value(f(v))
    case Error(_) ⇒ this.asInstanceOf[Error[E, W]]
  }

  def flatMap[F >: E, W](f: V ⇒ Maybe[F, W]): Maybe[F, W] = this match {
    case Value(v) ⇒ f(v)
    case Error(_) ⇒ this.asInstanceOf[Error[F, W]]
  }

  def flatMap[W](f: V ⇒ Future[W]): Future[Maybe[E, W]] = this match {
    case Value(v) ⇒ f(v).map(Value(_))
    case Error(_) ⇒ Future.successful(this.asInstanceOf[Error[E, W]])
  }
}

final case class Value[+E, +V](value: V) extends Maybe[E, V]    
final case class Error[+E, +V](error: E) extends Maybe[E, V]

但是,当我使用for comprehension组合MaybeFuture来保存另一个Maybe时,Scala编译器会在行中给出错误消息missing parameter type外部发电机:

def retrieveStreet(id: String): Future[Maybe[String, String]] = ...

val outerMaybe: Maybe[String, String] = ...

val result = for {
      id ← outerMaybe // error message "missing parameter type" here!
      street ← retrieveStreet(id)
    } yield street

但是,当我没有使用for而是明确地调用flatMapmap方法时,它会起作用:

val result2 =
  outerMaybe.flatMap( id => retrieveStreet(id) )
            .map( street => street )

(当我尝试将Maybe与另一个Maybe合并以进行理解时,我也收到此错误消息。)

所以问题是:

  1. 这两种选择不应该完全一样吗?为什么编译器在明确调用flatMap时会找出要调用的正确flatMap方法?

  2. 由于显然编译器被两个flatMap实现混淆了,有没有办法告诉它(通过任何地方的类型规范)应该在for comprehension中调用哪一个?

  3. 我在Eclipse中使用Scala 2.11.8。

1 个答案:

答案 0 :(得分:0)

我不能给你一个全面的答案,但是通过scalac -Xprint:parser运行,我可以告诉你,这2个替代方案实际上略有不同,这很可能是你问题的根源。

val result1 = outerMaybe
  .flatMap(((id) => retrieveStreet(id)
  .map(((street) => street))));

val result2 = outerMaybe
  .flatMap(((id) => retrieveStreet(id)))
  .map(((street) => street))