Scalafiddle 中的 Simulacrum:宏扩展期间的异常
Simulacrum in Scalafiddle: exception during macro expansion
我想在 Scalafiddle 中使用 Simulacrum,例如:
import simulacrum._
@typeclass trait Ordering[T] {
def compare(x: T, y: T): Int
@op("<") def lt(x: T, y: T): Boolean = compare(x, y) < 0
@op(">") def gt(x: T, y: T): Boolean = compare(x, y) > 0
}
这给了我以下错误:
ScalaFiddle.scala:3: error: exception during macro expansion:
scala.reflect.macros.TypecheckException: not found: type op
at scala.reflect.macros.contexts.Typers.$anonfun$typecheck(Typers.scala:32)
...
这是fiddle:https://scalafiddle.io/sf/vT0X9FR/4
我是不是漏掉了什么?
你的代码没有问题,问题出在ScalaFiddle。
如果我尝试 运行 你在 scastie 中的代码(类似于 Scala 的 web IDE),并打印出它生成的类型树,你可以看到以下内容:
|-- class Playground BYVALmode-EXPRmode (site: package <empty>)
| |-- new op("<") EXPRmode (silent: class Playground)
您可以看到 scastie 导致生成的代码被包裹在 Playground
class 中,这不是您的代码中定义的,而是网络为您提供的 IDE.
如果我在 IDEA 中编译相同的示例,我会看到以下内容:
|-- new op("<") EXPRmode (silent: package github)
| |-- new op BYVALmode-EXPRmode-FUNmode-POLYmode (silent: package github)
如您所见,没有由 simulacrum 创建的 op
类型的换行。由于这种包装,Simulacrum 无法找到它生成的 op
类型,因为它在编译时的完整命名空间是 Playground.op
.
为避免这种情况并作为解决方法,将您的特征包装在一个对象中:
import simulacrum._
object Foo {
@typeclass trait Ordering[T] {
def compare(x: T, y: T): Int
@op("<") def lt(x: T, y: T): Boolean = compare(x, y) < 0
@op(">") def gt(x: T, y: T): Boolean = compare(x, y) > 0
}
@typeclass trait Numeric[T] extends Ordering[T] {
@op("+") def plus(x: T, y: T): T
@op("*") def times(x: T, y: T): T
@op("unary_-") def negate(x: T): T
def zero: T
def abs(x: T): T = if (lt(x, zero)) negate(x) else x
}
import Foo.Numeric.ops._
def signOfTheTimes[T: Numeric](t: T): T = -(t.abs) * t
}
我想在 Scalafiddle 中使用 Simulacrum,例如:
import simulacrum._
@typeclass trait Ordering[T] {
def compare(x: T, y: T): Int
@op("<") def lt(x: T, y: T): Boolean = compare(x, y) < 0
@op(">") def gt(x: T, y: T): Boolean = compare(x, y) > 0
}
这给了我以下错误:
ScalaFiddle.scala:3: error: exception during macro expansion:
scala.reflect.macros.TypecheckException: not found: type op
at scala.reflect.macros.contexts.Typers.$anonfun$typecheck(Typers.scala:32)
...
这是fiddle:https://scalafiddle.io/sf/vT0X9FR/4
我是不是漏掉了什么?
你的代码没有问题,问题出在ScalaFiddle。
如果我尝试 运行 你在 scastie 中的代码(类似于 Scala 的 web IDE),并打印出它生成的类型树,你可以看到以下内容:
|-- class Playground BYVALmode-EXPRmode (site: package <empty>)
| |-- new op("<") EXPRmode (silent: class Playground)
您可以看到 scastie 导致生成的代码被包裹在 Playground
class 中,这不是您的代码中定义的,而是网络为您提供的 IDE.
如果我在 IDEA 中编译相同的示例,我会看到以下内容:
|-- new op("<") EXPRmode (silent: package github)
| |-- new op BYVALmode-EXPRmode-FUNmode-POLYmode (silent: package github)
如您所见,没有由 simulacrum 创建的 op
类型的换行。由于这种包装,Simulacrum 无法找到它生成的 op
类型,因为它在编译时的完整命名空间是 Playground.op
.
为避免这种情况并作为解决方法,将您的特征包装在一个对象中:
import simulacrum._
object Foo {
@typeclass trait Ordering[T] {
def compare(x: T, y: T): Int
@op("<") def lt(x: T, y: T): Boolean = compare(x, y) < 0
@op(">") def gt(x: T, y: T): Boolean = compare(x, y) > 0
}
@typeclass trait Numeric[T] extends Ordering[T] {
@op("+") def plus(x: T, y: T): T
@op("*") def times(x: T, y: T): T
@op("unary_-") def negate(x: T): T
def zero: T
def abs(x: T): T = if (lt(x, zero)) negate(x) else x
}
import Foo.Numeric.ops._
def signOfTheTimes[T: Numeric](t: T): T = -(t.abs) * t
}