繁体   English   中英

Scala:用于理解类型推断问题的多个flatMap定义

[英]Scala: Multiple flatMap definitions for for-comprehension type-inference issue

我有这样的事情:

case class Box[A](x: A) {
  def flatMap[B](f: A => GenTraversableOnce[B]): GenTraversableOnce[B] =
    f(x)

  def flatMap[B](f: A => Box[B]): Box[B] =
    f(x)

  def map[B](f: A => B): Box[B] =
    Box(f(x))
}

object Box {
  for {
    i <- Box(0)
    j <- Box(1)
  } yield i + j
}

上面的代码在Scala 2.12.4中可以正常编译,但是在Scala 2.11.12中不可以编译

[error] Box.scala:10: missing parameter type
[error]     i <- Box(0)
[error]     ^
[error] one error found
[error] (core/compile:compileIncremental) Compilation failed

为什么? 我究竟做错了什么??

然后,我尝试:

for {
  i: Int <- Box(0)
  j: Int <- Box(1)
} yield i + j

现在令人惊讶的是,该代码在Scala 2.11.12中进行编译,但在Scala 2.12.4中不进行编译

[error] Box.scala:10: pattern var i in value $anonfun is never used; `i@_' suppresses this warning
[error]     i: Int <- Box(0)
[error]     ^
[error] Box.scala:11: pattern var j in value $anonfun is never used; `j@_' suppresses this warning
[error]     j: Int <- Box(1)
[error]     ^
[error] two errors found
[error] (core/compile:compileIncremental) Compilation failed

这些是我正在使用的scalac标志:

def scalacOptionsForVersion(scalaVersion: String) = CrossVersion.partialVersion(scalaVersion) match {
  case Some((2, 10)) => Seq(
    "-deprecation",
    "-encoding", "UTF-8",
    "-feature",
    "-language:implicitConversions",
    "-language:reflectiveCalls",
    "-unchecked",
    "-Xfatal-warnings",
    "-Xlint",
    "-Yinline-warnings",
    "-Yno-adapted-args",
    "-Ywarn-dead-code",
    //"-Ywarn-numeric-widen",             // bugs in 2.10
    "-Xfuture"
  )
  case Some((2, 11)) => Seq(              // Copied from https://tpolecat.github.io/2014/04/11/scalac-flags.html
    "-deprecation",
    "-encoding", "UTF-8",                 // yes, this is 2 args
    "-feature",
    "-language:existentials",
    "-language:higherKinds",
    "-language:implicitConversions",
    "-unchecked",
    "-Xfatal-warnings",
    "-Xlint",
    "-Yno-adapted-args",
    "-Ywarn-dead-code",                  // N.B. doesn't work well with the ??? hole
    "-Ywarn-numeric-widen",
    //"-Ywarn-value-discard",            // This is broken in 2.11 for Unit types
    "-Xfuture",
    "-Ywarn-unused-import"               // 2.11 only
  )
  case Some((2, 12)) => Seq(             // Copied from https://tpolecat.github.io/2017/04/25/scalac-flags.html
    "-deprecation",                      // Emit warning and location for usages of deprecated APIs.
    "-encoding", "utf-8",                // Specify character encoding used by source files.
    "-explaintypes",                     // Explain type errors in more detail.
    "-feature",                          // Emit warning and location for usages of features that should be imported explicitly.
    "-language:existentials",            // Existential types (besides wildcard types) can be written and inferred
    "-language:experimental.macros",     // Allow macro definition (besides implementation and application)
    "-language:higherKinds",             // Allow higher-kinded types
    "-language:implicitConversions",     // Allow definition of implicit functions called views
    "-unchecked",                        // Enable additional warnings where generated code depends on assumptions.
    "-Xcheckinit",                       // Wrap field accessors to throw an exception on uninitialized access.
    "-Xfatal-warnings",                  // Fail the compilation if there are any warnings.
    "-Xfuture",                          // Turn on future language features.
    "-Xlint:adapted-args",               // Warn if an argument list is modified to match the receiver.
    "-Xlint:by-name-right-associative",  // By-name parameter of right associative operator.
    "-Xlint:constant",                   // Evaluation of a constant arithmetic expression results in an error.
    "-Xlint:delayedinit-select",         // Selecting member of DelayedInit.
    "-Xlint:doc-detached",               // A Scaladoc comment appears to be detached from its element.
    "-Xlint:inaccessible",               // Warn about inaccessible types in method signatures.
    "-Xlint:infer-any",                  // Warn when a type argument is inferred to be `Any`.
    "-Xlint:missing-interpolator",       // A string literal appears to be missing an interpolator id.
    "-Xlint:nullary-override",           // Warn when non-nullary `def f()' overrides nullary `def f'.
    "-Xlint:nullary-unit",               // Warn when nullary methods return Unit.
    "-Xlint:option-implicit",            // Option.apply used implicit view.
    "-Xlint:package-object-classes",     // Class or object defined in package object.
    "-Xlint:poly-implicit-overload",     // Parameterized overloaded implicit methods are not visible as view bounds.
    "-Xlint:private-shadow",             // A private field (or class parameter) shadows a superclass field.
    "-Xlint:stars-align",                // Pattern sequence wildcard must align with sequence component.
    "-Xlint:type-parameter-shadow",      // A local type parameter shadows a type already in scope.
    "-Xlint:unsound-match",              // Pattern match may not be typesafe.
    "-Yno-adapted-args",                 // Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver.
    "-Ypartial-unification",             // Enable partial unification in type constructor inference
    "-Ywarn-dead-code",                  // Warn when dead code is identified.
    "-Ywarn-extra-implicit",             // Warn when more than one implicit parameter section is defined.
    "-Ywarn-inaccessible",               // Warn about inaccessible types in method signatures.
    "-Ywarn-infer-any",                  // Warn when a type argument is inferred to be `Any`.
    "-Ywarn-nullary-override",           // Warn when non-nullary `def f()' overrides nullary `def f'.
    "-Ywarn-nullary-unit",               // Warn when nullary methods return Unit.
    "-Ywarn-numeric-widen",              // Warn when numerics are widened.
    "-Ywarn-unused:implicits",           // Warn if an implicit parameter is unused.
    "-Ywarn-unused:imports",             // Warn if an import selector is not referenced.
    "-Ywarn-unused:locals",              // Warn if a local definition is unused.
    "-Ywarn-unused:params",              // Warn if a value parameter is unused.
    "-Ywarn-unused:patvars",             // Warn if a variable bound in a pattern is unused.
    "-Ywarn-unused:privates",            // Warn if a private member is unused.
    "-Ywarn-value-discard"               // Warn when non-Unit expression results are unused.
  )
  case _ => throw new IllegalArgumentException(s"No scalacOptions found for Scala $scalaVersion")
}

如何编写此代码,使其在Scala 2.11.x和2.12.x中都可以编译而无需显式类型?

它不是完美的,但是您可以使用基于隐式的解决方案来代替重载。

import scala.collection.GenTraversableOnce

case class Box[A](x: A) {
  def flatMap[B, F[_]](f: A => F[B])(implicit fmap: Box.FlatMap[F]): F[B] =
    fmap(x)(f)

  def map[B](f: A => B) = Box(f(x))
}

object Box {
  sealed trait FlatMap[F[_]] {
    def apply[A, B](a: A)(f: A => F[B]): F[B]
  }
  implicit val GenTraversableOnceFM = new FlatMap[GenTraversableOnce] {
    def apply[A, B](a: A)(f: A => GenTraversableOnce[B]) = f(a)
  }
  implicit val BoxFM = new FlatMap[Box] {
    def apply[A, B](a: A)(f: A => Box[B]) = f(a)
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM