В вашем коде нет ничего плохого, проблема в 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
}