Using a class of type Numeric
in an Interval
object has a parameter of type T
, which must be bound somewhere in its scope. Interval
, being a unique constant value, cannot provide this binding.
One solution to this particular problem would be to move the definitions of your union
and intersect
operations to the Interval
class as normal instance methods, in which case they would share the T
binding and the associated Numeric
instance with the rest of the class.
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) }
If, however, you prefer to keep the definitions of these operations separate from the Interval
class, one approach to reducing the number of implicit templates that you need to pursue through your APIs is to define your own type of higher-level classes in terms of Numeric [T]. For instance,
// 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]
to be used
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) }
The third option combines the two using an implicit definition to enrich the original class with additional methods,
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]
Then when using
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) }