scala - 对不兼容的类型(Double和DenseVector)使用-=会导致奇怪的Scala编译器错误

标签 scala compiler-errors scala-breeze

我对scala还是比较陌生,并且在使用scala编译器时遇到了最初完全没有信息的NullPointerException,现在我可以缩小问题范围并消除其原因,但我仍然不完全了解编译器的行为。
环境:
IntelliJ IDEA 2020.2.3,JDK 1.8.0_271,Scala 2.13.3,SBT 1.3.13,Breeze 1.1
编辑:在没有IntelliJ的情况下使用SBT 1.4.2从命令行使用sbt compile进行了验证,编译器行为完全相同
我目前正在观察的内容:
MWE:

import breeze.linalg._
object MWE {
  def test(v: DenseVector[Double], m: DenseMatrix[Double]): Unit = {
    var value = 0.5
    value += v
    value += 0.5 * v.t * m * v
 }
}
在该行的Double +=和DenseVector value上错误地使用运算符v
    value += v
在IDE中立即正确地以红色突出显示该内容。
尝试编译它,我得到了有用的信息
value += is not a member of Double
  Expression does not convert to assignment because:
    overloaded method + with alternatives:
      (x: Double)Double <and>
      (x: Float)Double <and>
      (x: Long)Double <and>
      (x: Int)Double <and>
      (x: Char)Double <and>
      (x: Short)Double <and>
      (x: Byte)Double
     cannot be applied to (breeze.linalg.DenseVector[Double])
    expansion: value = value.<$plus: error>(v)
    value += v
相反,错误地使用运算符-=,IDE 不会突出显示为红色。
尝试编译它,我得到了一个不同但仍有用的信息:
value -= is not a member of Double
  Expression does not convert to assignment because:
    type mismatch;
     found   : breeze.linalg.DenseVector[Double]
     required: Double
    expansion: value = value.<$minus: error>(v)
    value -= v
第一个问题:为什么这两种情况表现出不同的行为?
我对scala中的这些运算符进行了简短的处理(请参阅例如Where is Scala's += defined in the context of Int?),并在查看了scala文档(尤其是https://www.scala-lang.org/api/2.13.3/scala/Double.html)之后,看不出+=-=有区别的任何理由吗?
回到我们的原始代码,行为上的差异以另一种方式体现出来:
在行中使用+=
value += 0.5 * v.t * m * v
导致的行为与上述更简单的情况类似,这是因为右侧的操作会产生DenseVector类型的结果(有关更多信息,请参见下文),我们尝试将其添加到Double中。在IDE中,该运算符标记为红色,并且显示相同的编译器错误。
但是,与更简单的情况相比,使用-=会显示出完全不同的编译器错误:
scalac: Error while emitting MWE.scala
assertion failed: 
  Bad superClass for class Double: <none>
     while compiling: C:\Users\bt306644\typeBugMWE\src\main\scala\MWE.scala
        during phase: jvm
     library version: version 2.13.3
    compiler version: version 2.13.3
  reconstructed args: -classpath C:\Program Files\Java\jdk1.8.0_271\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\rt.jar;C:\Users\bt306644\typeBugMWE\target\scala-2.13\classes;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\com\chuusai\shapeless_2.13\2.3.3\shapeless_2.13-2.3.3.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\com\github\fommil\netlib\core\1.1.2\core-1.1.2.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\com\github\wendykierp\JTransforms\3.1\JTransforms-3.1.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\net\sf\opencsv\opencsv\2.3\opencsv-2.3.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\net\sourceforge\f2j\arpack_combined_all\0.1\arpack_combined_all-0.1.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\apache\commons\commons-math3\3.5\commons-math3-3.5.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\scala-lang\modules\scala-collection-compat_2.13\2.1.1\scala-collection-compat_2.13-2.1.1.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\scala-lang\scala-library\2.13.3\scala-library-2.13.3.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\scala-lang\scala-reflect\2.13.3\scala-reflect-2.13.3.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\scalanlp\breeze-macros_2.13\1.1\breeze-macros_2.13-1.1.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\scalanlp\breeze_2.13\1.1\breeze_2.13-1.1.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\slf4j\slf4j-api\1.7.5\slf4j-api-1.7.5.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\typelevel\algebra_2.13\2.0.0-M2\algebra_2.13-2.0.0-M2.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\typelevel\cats-kernel_2.13\2.0.0-M4\cats-kernel_2.13-2.0.0-M4.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\typelevel\machinist_2.13\0.6.8\machinist_2.13-0.6.8.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\typelevel\spire-macros_2.13\0.17.0-M1\spire-macros_2.13-0.17.0-M1.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\typelevel\spire-platform_2.13\0.17.0-M1\spire-platform_2.13-0.17.0-M1.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\typelevel\spire-util_2.13\0.17.0-M1\spire-util_2.13-0.17.0-M1.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\typelevel\spire_2.13\0.17.0-M1\spire_2.13-0.17.0-M1.jar;C:\Users\bt306644\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\pl\edu\icm\JLargeArrays\1.5\JLargeArrays-1.5.jar

  last tree to typer: Literal(Constant(0.5))
       tree position: line 6 of C:\Users\bt306644\typeBugMWE\src\main\scala\MWE.scala
            tree tpe: Double(0.5)
              symbol: null
           call site: constructor MWE in object MWE in package <empty>

== Source file context for tree position ==

     3   def test(v: DenseVector[Double], m: DenseMatrix[Double]): Unit = {
     4     var value = 0.5
     5 //    value += v
     6     value -= 0.5 * v.t * m * v
     7  }
     8 }
     9 
第二个问题:到底该告诉我什么,为什么会发生?

除了这些主要问题外,还有一些上下文信息和注意事项:
回到我遇到此问题的原始代码和设置的另一步,我们实际上使用的是Scala 2.11.11而不是2.13.3(因此使用Breeze 0.13.2而不是Breeze 1.1)。
这导致编译器在第二种情况下根本不显示任何有用的信息,而是在编译器中产生了NullPointerException:
scalac: Error: org.jetbrains.jps.incremental.scala.remote.ServerException
java.lang.NullPointerException
    at scala.tools.nsc.transform.Mixin$MixinTransformer.scala$tools$nsc$transform$Mixin$MixinTransformer$$postTransform(Mixin.scala:1154)
    at scala.tools.nsc.transform.Mixin$MixinTransformer$$anonfun$transform$1.apply(Mixin.scala:1261)
    at scala.tools.nsc.transform.Mixin$MixinTransformer$$anonfun$transform$1.apply(Mixin.scala:1261)
    at scala.reflect.internal.SymbolTable.enteringPhase(SymbolTable.scala:235)
    at scala.reflect.internal.SymbolTable.exitingPhase(SymbolTable.scala:256)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:1261)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:468)
    at scala.reflect.internal.Trees$class.itransform(Trees.scala:1347)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:1258)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:468)
    at scala.reflect.internal.Trees$class.itransform(Trees.scala:1386)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:1258)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:468)
    at scala.reflect.api.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:2589)
    at scala.reflect.api.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:2587)
    at scala.collection.immutable.List.loop$1(List.scala:176)
    at scala.collection.immutable.List.mapConserve(List.scala:200)
    at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2587)
    at scala.reflect.internal.Trees$class.itransform(Trees.scala:1366)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:1258)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:468)
    at scala.reflect.internal.Trees$$anonfun$itransform$2.apply(Trees.scala:1363)
    at scala.reflect.internal.Trees$$anonfun$itransform$2.apply(Trees.scala:1361)
    at scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2600)
    at scala.reflect.internal.Trees$class.itransform(Trees.scala:1360)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:1258)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:468)
    at scala.reflect.api.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:2589)
    at scala.reflect.api.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:2587)
    at scala.collection.immutable.List.loop$1(List.scala:176)
    at scala.collection.immutable.List.mapConserve(List.scala:200)
    at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2587)
    at scala.reflect.internal.Trees$class.itransform(Trees.scala:1404)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:1258)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:468)
    at scala.reflect.api.Trees$Transformer.transformTemplate(Trees.scala:2563)
    at scala.reflect.internal.Trees$$anonfun$itransform$4.apply(Trees.scala:1408)
    at scala.reflect.internal.Trees$$anonfun$itransform$4.apply(Trees.scala:1407)
    at scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2600)
    at scala.reflect.internal.Trees$class.itransform(Trees.scala:1406)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:1258)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:468)
    at scala.reflect.api.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:2589)
    at scala.reflect.api.Trees$Transformer$$anonfun$transformStats$1.apply(Trees.scala:2587)
    at scala.collection.immutable.List.loop$1(List.scala:176)
    at scala.collection.immutable.List.mapConserve(List.scala:200)
    at scala.reflect.api.Trees$Transformer.transformStats(Trees.scala:2587)
    at scala.reflect.internal.Trees$$anonfun$itransform$7.apply(Trees.scala:1426)
    at scala.reflect.internal.Trees$$anonfun$itransform$7.apply(Trees.scala:1426)
    at scala.reflect.api.Trees$Transformer.atOwner(Trees.scala:2600)
    at scala.reflect.internal.Trees$class.itransform(Trees.scala:1425)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
    at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:1258)
    at scala.tools.nsc.transform.Mixin$MixinTransformer.transform(Mixin.scala:468)
    at scala.tools.nsc.ast.Trees$Transformer.transformUnit(Trees.scala:147)
    at scala.tools.nsc.transform.Transform$Phase.apply(Transform.scala:30)
    at scala.tools.nsc.Global$GlobalPhase$$anonfun$applyPhase$1.apply$mcV$sp(Global.scala:467)
    at scala.tools.nsc.Global$GlobalPhase.withCurrentUnit(Global.scala:458)
    at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:467)
    at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:425)
    at scala.tools.nsc.Global$GlobalPhase$$anonfun$run$1.apply(Global.scala:425)
    at scala.collection.Iterator$class.foreach(Iterator.scala:891)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1334)
    at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:425)
    at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1528)
    at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1513)
    at scala.tools.nsc.Global$Run.compileSources(Global.scala:1508)
    at scala.tools.nsc.Global$Run.compile(Global.scala:1609)
    at xsbt.CachedCompiler0.run(CompilerInterface.scala:130)
    at xsbt.CachedCompiler0.run(CompilerInterface.scala:105)
    at xsbt.CompilerInterface.run(CompilerInterface.scala:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sbt.internal.inc.AnalyzingCompiler.call(AnalyzingCompiler.scala:237)
    at sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:111)
    at sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:90)
    at org.jetbrains.jps.incremental.scala.local.IdeaIncrementalCompiler.compile(IdeaIncrementalCompiler.scala:42)
    at org.jetbrains.jps.incremental.scala.local.LocalServer.compile(LocalServer.scala:43)
    at org.jetbrains.jps.incremental.scala.remote.Main$.compileLogic(Main.scala:145)
    at org.jetbrains.jps.incremental.scala.remote.Main$.$anonfun$handleCommand$1(Main.scala:131)
    at org.jetbrains.jps.incremental.scala.remote.Main$.decorated$1(Main.scala:121)
    at org.jetbrains.jps.incremental.scala.remote.Main$.handleCommand(Main.scala:128)
    at org.jetbrains.jps.incremental.scala.remote.Main$.serverLogic(Main.scala:105)
    at org.jetbrains.jps.incremental.scala.remote.Main$.nailMain(Main.scala:63)
    at org.jetbrains.jps.incremental.scala.remote.Main.nailMain(Main.scala)
    at sun.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.martiansoftware.nailgun.NGSession.run(NGSession.java:319)
由于我完全没有暗示NPE的起因,因此需要一些时间来缩小范围。 NPE似乎是scala编译器中的错误,该错误已在2.13中修复,请参见例如。 https://github.com/scala/bug/issues/8583(如果在此处假设连接有误,请纠正我吗?)。
实际导致这整个东西出现的原因还有些奇怪(不,我没想到能够从Double xD中减去DenseVectors)。
初始代码中的操作稍微复杂一些,但实际上可以归结为MWE中的这一行:
value -= 0.5 * v.t * m * v
实际上,这根本不应该产生DenseVector!
撇开0.5,我们将转置的 vector ,方矩阵和 vector 相乘,它们都具有相同的尺寸。此操作导致标量,而不是 vector !
但是0.5至少会在代码中造成困惑(至少在类型方面如此)-将标量乘以转置的DenseVector(0.5 * v.t)不会得到预期的转置的DenseVector,结果是DenseMatrix类型的。然后,这导致整行导致DenseVector的类型错误,而不是Double。
附加问题:代码为什么显示有关类型的这种行为?任何人都知道这是否是一个合理的选择,或者甚至可能是Breeze中的错误?
因此事实证明,通过添加括号可以很容易地修复我们的原始代码:
value -= 0.5 * (v.t * m * v)
正确地导致增加了两个Double,一切都很好。
但是问题的原因仍然让我感到困惑,我期待收到一些有用的信息:)

最佳答案

第一个问题:这是有根据的猜测。 Scala对++=的处理有些怪异,因为Scala可以让您执行(x: Any) + (y: String),而且我已经看到了由此引起的不同运算符的错误怪异。
第二个问题:这是一个编译器错误,应该受到支持。您可以尝试在scalac中使用-no-specialization标志运行,看看是否遇到相同的错误。特化在Breeze中使用很多,多年来,我偶然发现了许多与之相关的编译器错误。
附带问题:这是Breeze中的限制/错误。 Scala将.5 * v.t * m * v解析为0.5.*(v.t).*(m).*(v)(即从左到右)。 v.tTranspose[DenseVector[Double]](即行 vector ),说实话,Transpose的东西并没有我想要的完全烘焙。从历史上讲,我们将行 vector 表示为矩阵,但我怀疑它会回落到那,因此它看到矩阵*矩阵* vector 当然是 vector 。

关于scala - 对不兼容的类型(Double和DenseVector)使用-=会导致奇怪的Scala编译器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64753094/

相关文章:

scala - sbt 添加设置的惯用方式

scala - 在 Scala 中打印下 X 行

scala - 为什么我要使用 type T = <type> 而不是 Trait[T]?

gcc - 编译6.3.0 gcc时声明冲突

java - 开始Java : Printing out a 5 pointed star using arrays

c# - 三元条件下的隐式转换问题

scala - 如何使用 scala/breeze 读取 hdf5 矩阵?

scala - scala 2.10 编译器中 scala.language.dynamics 错误的解决方法

java - Play 应用中 POST 的内部重定向?