Simulacrum в Scalafiddle: исключение при расширении макроса - PullRequest
0 голосов
/ 19 октября 2018

Я хотел использовать Simulacrum в Scalafiddle, например:

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$3(Typers.scala:32)
    ...

Вот скрипка: https://scalafiddle.io/sf/vT0X9FR/4

Я что-то пропустил?

1 Ответ

0 голосов
/ 19 октября 2018

В вашем коде нет ничего плохого, проблема в ScalaFiddle.

Если я попытаюсь запустить ваш код в scastie (аналог веб-IDE для Scala) и распечатать сгенерированные им деревья типов, вы увидите следующее:

|-- class Playground BYVALmode-EXPRmode (site: package <empty>) 
|    |-- new op("<") EXPRmode (silent: class Playground) 

Вы можете видеть, что scastie вызывает создание сгенерированного кода внутри класса Playground, который не определен в вашем коде, но предоставлен для вас в веб-среде IDE.

Если я компилируюВ том же примере в IDEA я вижу следующее:

|-- new op("<") EXPRmode (silent: package github) 
|    |-- new op BYVALmode-EXPRmode-FUNmode-POLYmode (silent: package github) 

Как видите, обтекания типа op, созданного simulacrum, не существует.Из-за этого переноса 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
}
...