Skip to content

Instantly share code, notes, and snippets.

@yasuabe
Last active December 26, 2017 06:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yasuabe/f27a6f4bcac5f2d213008748c278ea96 to your computer and use it in GitHub Desktop.
Save yasuabe/f27a6f4bcac5f2d213008748c278ea96 to your computer and use it in GitHub Desktop.
product_code(redefine+cats+scalacheck)
package ratio1
import cats.Eq
import eu.timepit.refined.refineV
import eu.timepit.refined.api.Refined
import eu.timepit.refined.boolean.Not
import eu.timepit.refined.generic.Equal
import eu.timepit.refined.{W, refineMV}
import shapeless.Nat._0
trait NonZeroIntModule {
type NonZero = Not[Equal[_0]]
type NonZeroInt = Int Refined NonZero
object NonZeroInt {
val one: NonZeroInt = refineMV[NonZero](1)
}
implicit class NonZeroIntOps(val nz: NonZeroInt) {
def *(r: NonZeroInt): NonZeroInt =
refineV[NonZero]((nz, r).foldMap(_.value)(_ * _)).toOption.get
}
}
trait RationalModule {
import Rational._
case class Rational(n: Int, d: NonZeroInt) {
def +(r: Rational): Rational = apply(r.d.value * n + d.value * r.n, d * r.d)
def *(r: Rational): Rational = apply(n * r.n, d * r.d)
def negate: Rational = apply(n * (-1), d)
def invert: MaybeRational = refineV[NonZero](n).map(Rational(d.value, _))
}
object Rational {
type MaybeRational = Either[String, Rational]
val zero: Rational = apply(0, NonZeroInt.one)
val one: Rational = apply(1, NonZeroInt.one)
def apply(num: Int, denom: NonZeroInt): Rational =
(new Rational(_, _)) tupled reduce(num, denom)
def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
def reduce(n0: Int, nz: NonZeroInt): (Int, NonZeroInt) = {
val f = (b: Int) => (n0, b).map(_ / gcd(n0, b))
f(nz.value) match { case (n, d) => (n, refineV[NonZero](d).toOption.get) }
}
}
implicit val eqRational: Eq[Rational] = (x, y) => x == y
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment