Hello. Here’s a problem I cannot solve:
Out of fun I’m writing a library to play with numbers, specifically Rationals:
package loonies
final case class Rational(
val numerator: Long,
val denominator: Long)
extends Number {
require(denominator != 0, "The denominator cannot be zero")
val value = (numerator, denominator)
def +(rhs: Rational) =
Rational((numerator * rhs.denominator + denominator * rhs.numerator),
(denominator * rhs.denominator))
def +(rhs: Integer) =
Rational(numerator + rhs.value._1 * denominator, denominator)
override def toString: String = s"Q{${numerator}/$denominator}"
}
Integers:
package loonies
final case class Integer(val numero: Long) extends Number {
val value = (numero, 1L)
//val num = numero
def +(rhs: Integer): Integer = new Integer(numero + rhs.numero)
def +(rhs: Rational): Rational =
Rational(value._1 * rhs.denominator + rhs.numerator, rhs.denominator)
def -(rhs: Integer): Integer = new Integer(numero - rhs.numero)
def *(rhs: Integer): Integer = new Integer(numero * rhs.numero)
/**
* This operator tests if `this` Integer '''divides''' `that`
* Integer
*/
def |(rhs: Integer): Boolean = rhs.numero match {
case s if (s % numero == 0) => true
case _ => false
}
override def toString: String = s"Z{${numero}}"
}
and, finally, the Supertype Number:
package loonies
trait Number {
import Number._
def value: (Long, Long)
/**
* This operator should return the result of the division of two integers `a'
* and `b` if `b` divides `a`, otherwise a Rational number with `a` as
* numerator and `b` as denominator
*/
def /(that: Number): Number = that match {
case t: Integer =>
this match {
case s: Integer if t | s => num(s.numero / t.numero)
case s: Integer if !(t | s) => num(s.numero, t.numero)
}
}
}
object Number {
def num(l: Long) = Integer(l)
def num(
n: Long,
d: Long
) = new Rational(n, d)
}
Now, my focus is on the /
operator of the latter class: given two Integers a
and b
, if b|a
I’ll get another Integer c = a ÷ b
otherwise a Rational with a
as its numerator and b
its denominator.
So if I use them I get:
scala> import loonies._
import loonies._
scala> val a = Integer(5)
a: loonies.Integer = Z{5}
scala> val b = Integer(15)
b: loonies.Integer = Z{15}
scala> val c = b / a
c: loonies.Number = Z{3}
scala> val q = a / b
q: loonies.Number = Q{5/15}
scala> c + q
^
error: type mismatch;
found : loonies.Number
required: String
scala> q + c
^
error: type mismatch;
found : loonies.Number
required: String
scala> val s = c + q
^
error: type mismatch;
found : loonies.Number
required: String
So, it looks like that, even if Rationals and Integers have operators overloaded so to deal with each other, still, I would have to write nested methods to allow Number to tackle the situation.
Anyone with any idea on how to circumvent, if possible, the problem?
Thanks
Guido