Los usos de la clase de tipo Numeric
en el objeto Interval
tienen un parámetro de tipo T
que debe vincularse en algún lugar de su ámbito adjunto. Interval
, al ser un valor constante único, no puede proporcionar ese enlace.
Una solución a este problema específico sería mover las definiciones de sus union
y intersect
operaciones en las Interval
clase métodos de instancia como ordinarias, en cuyo caso que compartirían la unión de T
y el asociado Numeric
instancia con el resto de la clase,
case class Interval[T : Numeric](from: T, to: T) {
import Numeric.Implicits._
import Ordering.Implicits._
def mid: Double = (from.toDouble + to.toDouble)/2.0
def union(interval2: Interval[T]) =
Interval(this.from min interval2.from, this.to max interval2.to)
def intersect(interval2: Interval[T]) =
Interval(this.from max interval2.from, this.to min interval2.to)
}
Si, sin embargo, prefiere mantener las definiciones de estas operaciones separar del Interval
clase, un enfoque para reducir la cantidad de texto modelo implícito que es necesario perseguir throug h sus API es definir sus propias clases de tipo de nivel superior en términos de Numérico [T]. Por ejemplo,
// Type class supplying union and intersection operations for values
// of type Interval[T]
class IntervalOps[T : Numeric] {
import Ordering.Implicits._
def union(interval1: Interval[T], interval2: Interval[T]) =
Interval[T](interval1.from min interval2.from, interval1.to max interval2.to)
def intersect(interval1: Interval[T], interval2: Interval[T]) =
Interval[T](interval1.from max interval2.from, interval1.to min interval2.to)
}
implicit def mkIntervalOps[T : Numeric] = new IntervalOps[T]
que en uso se vería así,
def use[T](i1 : Interval[T], i2 : Interval[T])(implicit ops : IntervalOps[T]) = {
import ops._
val i3 = union(i1, i2)
val i4 = intersect(i1, i2)
(i3, i4)
}
Una tercera opciones combina estos dos, utilizando una definición implícita para enriquecer la clase original con los métodos adicionales,
class IntervalOps[T : Numeric](interval1 : Interval[T]) {
import Ordering.Implicits._
def union(interval2: Interval[T]) =
Interval[T](interval1.from min interval2.from, interval1.to max interval2.to)
def intersect(interval2: Interval[T]) =
Interval[T](interval1.from max interval2.from, interval1.to min interval2.to)
}
implicit def enrichInterval[T : Numeric](interval1 : Interval[T]) =
new IntervalOps[T](interval1)
type Ops[T] = Interval[T] => IntervalOps[T]
Luego en uso,
def use[T](i1 : Interval[T], i2 : Interval[T])(implicit ops : Ops[T]) = {
val i3 = i1 union i2
val i4 = i1 intersect i2
(i3, i4)
}
Gracias. Buena brevedad. Nunca he visto esta idea ligada al contexto. ¿Dónde uno aprende tales cosas? Leí un libro sobre Scala, pero no recuerdo los límites del contexto. –
Ver por ejemplo [¿Qué es un "contexto vinculado" en Scala?] (Http://stackoverflow.com/questions/2982276/what-is-a-context-bound-in-scala). – Jesper