Как сравнить упорядоченный абстрактный тип в признаке Scala? - PullRequest
5 голосов
/ 13 февраля 2012

Учитывая код, указанный ниже, метод foo должен сравнивать с точки зрения оператора данный параметр bar с lowerBound и upperBound, все они имеют один и тот же абстрактный тип Bar.

trait Foo {
  type Bar <: Ordered[Bar]
  val lowerBound: Bar
  val upperBound: Bar
  def foo(bar: Bar) = bar >= lowerBound && bar <= upperBound
}

Таким образом, можно определить черту Foo.Проблемы начинаются с приведенного ниже конкретного класса FooImpl.

class FooImpl extends Foo {
  type Bar = Int
  val lowerBound = 0
  val upperBound = 5
}

Я понимаю, что scala.Int не реализует то, что делает scala.runtime.RichInt, эффективно scala.math.Ordered[Int].Определение типа Bar как RichInt взамен не работает, так как не соответствует scala.math.Ordered[RichInt].Моя третья попытка определить тип Bar как Ordered[Ord], где Ord объявлен как type Ord, и определение его в FooImpl как Int также не сработало.

Как было бы возможно закрытьрешение выглядит?

1 Ответ

8 голосов
/ 13 февраля 2012

Может быть более элегантное решение, но вы можете достичь этого, перенеся ограничение на тип в метод, а не на объявление типа:

trait Foo {
  type Bar
  val lowerBound: Bar
  val upperBound: Bar
  def foo(bar: Bar)(implicit ev: Bar => Ordered[Bar]) = {
    bar >= lowerBound && bar <= upperBound
  }
}

Тогда ваш FooImpl будет работать как выимейте это:

class FooImpl extends Foo {
  type Bar = Int
  val lowerBound = 0
  val upperBound = 5
}

Из REPL:

scala> new FooImpl()
res0: FooImpl = FooImpl@2dbbec72

scala> res0.foo(3)
res1: Boolean = true

scala> res0.foo(7)
res2: Boolean = false

Недостатком здесь является то, что признак может быть расширен с неупорядоченными типами (хотя foo не может быть вызван в этомcase):

class A // not Ordered

class BrokenFoo extends Foo {
  type Bar = A
  val lowerBound = new A
  val upperBound = new A
} // compiles

new BrokenFoo().foo(new A) // doesn't compile

В качестве альтернативы вы можете сохранить требование на уровне класса (и, следовательно, прекратить создание любого BrokenFoo) следующим образом, но FooImpl должно измениться незначительно:

trait Foo {
  type Bar
  implicit val baz: Bar => Ordered[Bar]
  val lowerBound: Bar
  val upperBound: Bar
  def foo(bar: Bar) = { bar >= lowerBound && bar <= upperBound }
}

class FooImpl extends Foo {
  type Bar = Int
  val baz = implicitly[Bar => Ordered[Bar]]
  val lowerBound = 0
  val upperBound = 5
}

Эта проблема выглядит так: границы представления или контекста должны быть применимы, но, к сожалению, не похоже, что вы можете использовать их либо в объявлениях type, либо в параметрах универсального типа для признаков.

...