我正在与项目中的猫一起工作,并且无法弄清楚为什么在这段代码中出现这种奇怪的编译器错误:
带有:Int
的scala> :paste
:paste
// Entering paste mode (ctrl-D to finish)
object Test {
def exec[F[_]: cats.Monad] = for {i: Int <- cats.data.EitherT.fromEither[F](Right(0))} yield i
}
^D
// Exiting paste mode, now interpreting.
<pastie>:12: error: value withFilter is not a member of cats.data.EitherT[F,E,Int]
def exec[F[_]: cats.Monad] = for {i: Int <- cats.data.EitherT.fromEither[F](Right(0))} yield i
:Int
它会编译对此错误的修复是不明确地注释<-
的左手参数。因此,请在此处留下类型提示: Int
:
scala> :paste
:paste
// Entering paste mode (ctrl-D to finish)
object Test {
def exec[F[_]: cats.Monad] = for {i <- cats.data.EitherT.fromEither[F](Right(0))} yield i
}
^D
// Exiting paste mode, now interpreting.
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
defined object Test
"org.typelevel" %% "cats-core" % "1.1.0"
"org.typelevel" %% "cats-macros" % "1.1.0"
"org.typelevel" %% "cats-kernel" % "1.1.0"
sbt about
sbt:cats-eithert-problem> about
[info] This is sbt 1.1.4
[info] The current project is ProjectRef(uri("file:/Users/isaias/Projects/cats-eithert-problem/"), "root") 0.1.0-SNAPSHOT
[info] The current project is built against Scala 2.12.5
[info] Available Plugins: sbt.plugins.IvyPlugin, sbt.plugins.JvmPlugin, sbt.plugins.CorePlugin, sbt.plugins.JUnitXmlReportPlugin, sbt.plugins.Giter8TemplatePlugin, com.timushev.sbt.updates.UpdatesPlugin, spray.revolver.RevolverPlugin, com.typesafe.sbt.SbtNativePackager, com.typesafe.sbt.packager.archetypes.JavaAppPackaging, com.typesafe.sbt.packager.archetypes.JavaServerAppPackaging, com.typesafe.sbt.packager.archetypes.jar.ClasspathJarPlugin, com.typesafe.sbt.packager.archetypes.jar.LauncherJarPlugin, com.typesafe.sbt.packager.archetypes.scripts.AshScriptPlugin, com.typesafe.sbt.packager.archetypes.scripts.BashStartScriptPlugin, com.typesafe.sbt.packager.archetypes.scripts.BatStartScriptPlugin, com.typesafe.sbt.packager.archetypes.systemloader.SystemVPlugin, com.typesafe.sbt.packager.archetypes.systemloader.SystemdPlugin, com.typesafe.sbt.packager.archetypes.systemloader.SystemloaderPlugin, com.typesafe.sbt.packager.archetypes.systemloader.UpstartPlugin, com.typesafe.sbt.packager.debian.DebianDeployPlugin, com.typesafe.sbt.packager.debian.DebianPlugin, com.typesafe.sbt.packager.debian.JDebPackaging, com.typesafe.sbt.packager.docker.DockerPlugin, com.typesafe.sbt.packager.docker.DockerSpotifyClientPlugin, com.typesafe.sbt.packager.jdkpackager.JDKPackagerDeployPlugin, com.typesafe.sbt.packager.jdkpackager.JDKPackagerPlugin, com.typesafe.sbt.packager.linux.LinuxPlugin, com.typesafe.sbt.packager.rpm.RpmDeployPlugin, com.typesafe.sbt.packager.rpm.RpmPlugin, com.typesafe.sbt.packager.universal.UniversalDeployPlugin, com.typesafe.sbt.packager.universal.UniversalPlugin, com.typesafe.sbt.packager.windows.WindowsDeployPlugin, com.typesafe.sbt.packager.windows.WindowsPlugin
[info] sbt, sbt plugins, and build definitions are using Scala 2.12.4
sbt console
sbt:cats-eithert-problem> console
[info] Starting scala interpreter...
Welcome to Scala 2.12.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
Type in expressions for evaluation. Or try :help.
有人知道为什么这段代码只有在使用相应类型明确注释时才会依赖withFilter
,或者这是一个错误?
答案 0 :(得分:2)
被编译为flatMap
,map
和withFilter
的组合。 withFilter
用于for comprehension的if
子句,但即使没有if
,仍然会生成withFilter
- 请参阅explanation at better-monadic-for
答案 1 :(得分:1)
对于这两种情况,desugared代码看起来都不同。
sbt console
-Xprint:typer
将scalacOptions ++= Seq("-Xprint:typer")
添加到build.sbt
后,就可以在sbt console
上打印出去掉的代码:
: Int
def exec [F[_] >: [_]Nothing <: [_]Any](implicit evidence$1: cats.Monad[F]): cats.data.EitherT[F,Nothing,Int] = cats.data.EitherT.fromEither[F]
.apply[Nothing, Int](scala.`package`.Right.apply[Nothing, Int](0))(evidence$1)
.map[Int](((i: Int) => i))(evidence$1)
: Int
def <exec: error>[F[_] >: [_]Nothing <: [_]Any](implicit evidence$1: cats.Monad[F]): <error> = cats.data.EitherT.fromEither[F]
(Right(0)).<withFilter: error>((
(<check$ifrefutable$1: error>: <error>) =>
<check$ifrefutable$1: error>: @scala.unchecked match {
case (<i: error> @ (_: Int)) => true
case _ => false
}
)
)
.<map: error>(((i: Int) => i))
但是,我仍然不知道为什么显式案例会添加此withFilter
。编译器内部的策略似乎是 NOT 信任程序员给出的显式类型注释。
Here is some piece of reference一位同事与我分享,表明通常所有事情都是作为发电机LHS的模式处理的。
生成器p&lt; - e 从表达式 e 生成绑定,该表达式以某种方式与模式 p 匹配
现在我非常确定这是有意的而不是错误,虽然模式只是一个标识符的情况是优化未在给定的参考中记录,它在较小的例子中可见:
: Int
scala -Xprint:typer -e "for { i <- Option(0) } yield i"
[[syntax trees at end of typer]] // scalacmd2652417036573431085.scala
package <empty> {
object Main extends scala.AnyRef {
def <init>(): Main.type = {
Main.super.<init>();
()
};
def main(args: Array[String]): Unit = {
final class $anon extends scala.AnyRef {
def <init>(): <$anon: AnyRef> = {
$anon.super.<init>();
()
};
scala.Option.apply[Int](0).map[Int](((i: Int) => i))
};
{
new $anon();
()
}
}
}
}
: Int
scala -Xprint:typer -e "for { i: Int <- Option(0) } yield i"
[[syntax trees at end of typer]] // scalacmd7960547396256503452.scala
package <empty> {
object Main extends scala.AnyRef {
def <init>(): Main.type = {
Main.super.<init>();
()
};
def main(args: Array[String]): Unit = {
final class $anon extends scala.AnyRef {
def <init>(): <$anon: AnyRef> = {
$anon.super.<init>();
()
};
scala.Option.apply[Int](0).withFilter(((check$ifrefutable$1: Int) => (check$ifrefutable$1: Int @unchecked) match {
case (i @ (_: Int)) => true
case _ => false
})).map[Int](((i: Int) => i))
};
{
new $anon();
()
}
}
}
}