我可以让Scala在这里推断选项类型吗?

时间:2015-07-21 18:44:35

标签: scala coding-style type-inference

我想调用泛型函数f[X](...),在我的情况下,X恰好是Option[Y]。我尝试传递函数所需的Some[...]None X,但Scala坚持认为X属于Some[Y]类型。

  def flattenOptionMap[A, B](input : Map[A, Option[B]]) : Option[Map[A, B]] = {
    input.foldLeft[Option[Map[A,B]]] (Some(Map.empty)) {
      case (_, (_, None)) => None
      case (None, (_, _)) => None
      case (Some(acc), (key, Some(value))) => Some(acc + (key -> value))
    }
  }

在此示例中,我必须明确指定Option[Map[A,B]]应该用作foldLeft的泛型类型。所有必要的类型信息都已包含在上下文中,并且在我看来,输入繁琐的类型(如Option[Map[A,B]])往往不必要地大大降低了我的代码的可读性。

有没有办法让Scala最终推断出类型,或者避免复制粘贴整个类型?

2 个答案:

答案 0 :(得分:5)

当您使用Option(Map.empty[A, B])作为foldLeft的起始值时,Scala将推断出我在评论中所写的正确类型(并在答案中加入了buryhalo)。

我想补充一点,如果你愿意使用Scalaz,你可以使用sequence函数。

import scalaz._
import Scalaz._ 

val mapSome = Map(1 -> Some("a"), 2 -> Some("b"))
val mapNone = Map(1 -> Some("a"), 2 -> Some("b"), 3 -> None)

mapSome.sequence
flattenOptionMap(mapSome)
// Option[Map[Int,String]] = Some(Map(1 -> a, 2 -> b))

mapNone.sequence
flattenOptionMap(mapNone)
// Option[Map[Int,String]] = None

答案 1 :(得分:4)

如果您的目标是提高可读性,并从编译器获取帮助以推断类型,请尝试:

def flattenOptionMap[A, B](input: Map[A, Option[B]]) =
  input.foldLeft(Option(Map.empty[A, B])) {
    case (_, (_, None))                  => None
    case (None, (_, _))                  => None
    case (Some(acc), (key, Some(value))) => Some(acc + (key -> value))
  }

甚至更好:

def flattenOptionMap[A, B](input: Map[A, Option[B]]) =
  input.foldLeft(Option(Map.empty[A, B])) {
    case (Some(acc), (key, Some(value))) => Some(acc + (key -> value))
    case _                               => None
  }

甚至更好(在我看来):Peter Neyens的回答。使用sequence实例中的Traverse