Наличие синтаксического сахара параметра в scala

У меня есть немного синтаксического сахара для операций, которые зависят от объекта:

case class EllipticOperand (p : Point)
{
  def + (q : => Point) = curve.sum(p,q)
  def * (n : => BigInt) = curve.times(p,n)
}
implicit def PointToOperand(p : Point) = EllipticOperand(p)

case class EllipticMultiplier (n : BigInt)
{
def * (p : => Point) = curve.times(p,n)
}
implicit def BigIntToOperand (n : BigInt) = EllipticMultiplier(n)

Я хотел бы инкапсулировать некоторые class SyntacticSugar[Point](curve : main.Curve[Point]), чтобы использовать их в определениях других классов без необходимости копировать/вставлять их.

Я пытался использовать его таким образом:

val sugar = new util.SyntacticSugar(curve)
import sugar._

Однако это не работает, я не могу использовать + и * после.


person Théo Winterhalter    schedule 20.06.2014    source источник
comment
почему бы не трейт, который вы смешаете с каким-то другим классом?   -  person om-nom-nom    schedule 20.06.2014
comment
Проблема в том, что trait не поддерживает параметры, и мой синтаксический сахар каждый раз зависит от конкретной кривой. Кстати, спасибо.   -  person Théo Winterhalter    schedule 20.06.2014
comment
Вы определили класс SyntacticSugar следующим образом: class SyntacticSugar[Point](curve : main.Curve[Point])? Итак, Point в приведенном выше фрагменте кода - это не класс, а параметр типа?   -  person Jasper-M    schedule 20.06.2014
comment
Ну, Point действительно является параметром типа, но curve — это объект.   -  person Théo Winterhalter    schedule 20.06.2014


Ответы (1)


Если я реализую это так, как вы предлагаете, это просто работает...

case class Point(x: Int, y: Int)

trait Curve[T] {
  def sum(p: T, q: T): T
  def times(p: T, n: Int): T
}

// dummy implementation
class PointCurve extends Curve[Point] {
  override def sum(p: Point, q: Point) = Point(p.x+q.x, p.y+q.y)
  override def times(p: Point, n: Int) = Point(p.x*n, p.y*n)
}


object util {
  class SyntacticSugar[T](curve: Curve[T]){
    case class EllipticOperand(p: T){
      def +(q: =>T) = curve.sum(p, q)
      def *(n: =>Int) = curve.times(p,n)
    }
    implicit def point2Operand(p: T) = EllipticOperand(p)
  }
}

Теперь вы можете использовать + и * в качестве операторов для Point:

scala> val sugar = new util.SyntacticSugar(new PointCurve)
sugar: util.SyntacticSugar[Point] = util$SyntacticSugar@4ed4b486

scala> import sugar._
import sugar._

scala> Point(1,2) + Point(2,3)
res0: Point = Point(3,5)

scala> Point(1,2) * 3
res1: Point = Point(3,6)
person Jasper-M    schedule 20.06.2014
comment
У меня не работает, может потому что в другом файле? Если да, то это проблема, потому что я не буду помещать все свои классы в один и тот же. - person Théo Winterhalter; 21.06.2014
comment
Не обязательно иметь все классы в одном файле. Только SyntacticSugar, EllipticOperand и метод point2Operand должны находиться в одном файле, так как SyntacticSugar является классом, охватывающим два других. Какие ошибки вы получаете? В каких строках кода? - person Jasper-M; 21.06.2014
comment
Я получаю overloaded method value * with alternatives (...) cannot be applied to (Point) a * p, где a — это BigInt, а p — точка. (Я добавил синтаксический сахар для BigInt в своем первом сообщении). - person Théo Winterhalter; 21.06.2014
comment
Я думаю, вы делаете 5 * Point(1,2), но чтобы это сработало, вы должны делать BigInt(5) * Point(1,2). действительно странно то, что это по-прежнему не работает... implicitly[BigInt=>{def *(p: =>Point): Point }] находит подходящее неявное представление, но компилятор не применяет его, когда это необходимо. Я думаю, вам следует открыть отдельный вопрос для этой проблемы, потому что это довольно странно. - person Jasper-M; 21.06.2014
comment
Кажется, что если вы измените параметр по имени на параметр по значению (удалите =>), неявное преобразование действительно сработает. Все еще не совсем объясняет, почему это работает для Point * BigInt с параметрами по имени, но не для BigInt * Point... Похоже, комбинация параметров типа и параметров по имени смущает компилятор... - person Jasper-M; 21.06.2014
comment
Кстати, если вы хотите иметь возможность использовать нотацию 5 * Point(1,2) без явного создания BigInt, вы должны добавить третье неявное определение: implicit def int2Operand (n: Int) = EllipticMultiplier(n) - person Jasper-M; 21.06.2014
comment
Ну, для Int уже есть один, так что это не должно быть причиной проблемы. Кроме того, если я просто скопирую тело класса SyntacticSugar, он просто сработает. Поэтому странно, если мне когда-нибудь понадобится изменить свою реализацию. - person Théo Winterhalter; 21.06.2014