为什么这个scala fold会返回Equals类型?

时间:2015-02-09 10:37:16

标签: scala

我试图在scala中返回地图。这是我的代码:

    val interestRegEx = """(\w+) Interests \((.+ Interest)\)""".r
    val singleAttributes = Seq("Sport Interests (Some Interest):Running,Swimming","Something else:True")
    val interests = singleAttributes.map { x =>
      // e.g. ("Sport Interests (Some Interest)", "Running,Swimming") should
      // result in ("Sport Running" -> "Some Interest", "Sport Swimming" -> "Some Interest")
      val attVal = x.split(':')

      attVal(0) match {
        case interestRegEx(interestProduct, interestAmount) =>
          Some(attVal(1).split(",").map { i =>
            Map(s"$interestProduct $i" -> interestAmount)
          }.reduce(_ ++ _))
        case _ => None
      }
    }.fold(Map[String, String]())(_) //.reduce(_ + _)

问题是尝试将集合减少到单个Map [String,String]。我认为折叠可能会起作用,但是因为它之后我甚至不需要添加reduce(_ + _),但这也不起作用。

我不明白的部分是IntelliJ告诉我interests的类型为((Equals, Equals) => Equals) => Equals。 WTF?这些Equals来自何处,为什么不将所有地图一起添加以返回包含所有键的地图&值?

2 个答案:

答案 0 :(得分:1)

如果我们简化您的示例,我们将获得:

  val interests = Seq[String]().map { x =>
    Option[Map[String, String]](Map("k" -> "v"))
  }.fold(Map[String, String]())(_)

这意味着我们正在尝试fold Seq[Option[Map[String, String]]]初始值Map[String, String]()

def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)

fold定义我们可以看到编译器期望Option[Map[String, String]](折叠中的每个值)和Map[String, String](init值)应该是相同的类型。

如果您检查Option层次结构,您会看到:

Option - > Product - > Equals

Map我们有以下内容:

Map - > GenMap - > GenMapLike - > Equals(特征层次很复杂,可能存在另一个链)。

所以我们可以看到最近的常见类型是Equals

拼图的第二部分是(_)

编译器将其视为lambda的参数:

val interests = x => /*omited*/.fold(Map[String, String]())(x)

我们看到x(A1, A1) => A1。在我们的例子中它是:

(Equals, Equals) => Equals

fold的结果是A1,也是Equals

结果lambda类型是:

((Equals, Equals) => Equals) /*<< arg*/ => /*result >>*/ Equals

<强>更新

为了解决您的问题,我认为您应该使用:

.flatten.reduce(_ ++ _)

答案 1 :(得分:1)

当您获得ProductEquals这样的特征作为语句的推断类型时,您通常会认为某些高阶函数的类型不匹配。您通常不会获得AnyAnyRef,因为只有在某些类型的没有共同的情况下才会出现这些情况。对我而言,有一件事是fold的第二个参数只需要一个参数。令人惊讶的是,那种类型的东西,但它可能会给你提供你不期望的类型。

我认为你想要做的更像是:

val interestRegEx = """(\w+) Interests \((.+ Interest)\)""".r
val singleAttributes = Seq("Sport Interests (Some Interest):Running,Swimming","Something else:True")
val interests = singleAttributes.map { x =>
  // e.g. ("Sport Interests (Some Interest)", "Running,Swimming") should
  // result in ("Sport Running" -> "Some Interest", "Sport Swimming" -> "Some Interest")
  val attVal = x.split(':')

  attVal(0) match {
    case interestRegEx(interestProduct, interestAmount) =>
      attVal(1).split(",").map { i =>
        Map(s"$interestProduct $i" -> interestAmount)
      }.reduce(_ ++ _)
    case _ => Map.empty
  }
}.reduce(_ ++ _)

为此,我得到了:

scala> interests
res0: scala.collection.immutable.Map[_ <: String, String] = Map(Sport Running -> Some Interest, Sport Swimming -> Some Interest)

我摆脱了Option在你的正则表达式匹配中包裹Map s。由于您计划组合地图,因此可以使用空地图作为不匹配的情况。然后我使用reduce代替fold进行最后一场比赛,就像你在内部map中所做的那样。