Rolling your own

Let’s say we want to code up a game of Catan. SI units don’t cut the mustard, so let’s make our own. Our base dimensions are going to be Stone, Wood, Wheat, Sheep and Time.

import libra._, libra.ops.base._

object catan {
  type Stone
  type Wood
  type Wheat
  type Sheep
  type Time
  
  type Rock = UnitOfMeasure[Stone]
  type Log = UnitOfMeasure[Wood]
  type Bushel = UnitOfMeasure[Wheat]
  type Flock = UnitOfMeasure[Sheep]
  type Turn = UnitOfMeasure[Time]
  
  
  //we ought to provide shows
  implicit def stoneShow: Show[Stone] = Show[Stone]("S")
  implicit def woodShow: Show[Wood] = Show[Wood]("W")
  implicit def wheatShow: Show[Wheat] = Show[Wheat]("F")
  implicit def sheepShow: Show[Sheep] = Show[Sheep]("B")
  implicit def timeShow: Show[Time] = Show[Time]("T")
  
  implicit def rockShow: Show[Rock] = Show[Rock]("Rock")
  implicit def logShow: Show[Log] = Show[Log]("Log")
  implicit def bushelShow: Show[Bushel] = Show[Bushel]("Bushel")
  implicit def flockShow: Show[Flock] = Show[Flock]("Flock")
  implicit def turnShow: Show[Turn] = Show[Turn]("Turn")
  
  
  //implicit conversions would be useful too
  implicit final class CatanOps[A](val a: A) {
     def logs: QuantityOf[A, Wood, Log] = Quantity(a)
     def rocks: QuantityOf[A, Stone, Rock] = Quantity(a)
     def flocks: QuantityOf[A, Sheep, Flock] = Quantity(a)
     def turns: QuantityOf[A, Time, Turn] = Quantity(a)
  }
}

import spire.implicits._
import catan._

val tradingRate = 4.0.logs / 1.0.flocks
// tradingRate: Quantity[Double, shapeless.::[(UnitOfMeasure[Wood], Fraction[1, 1]) with shapeless.labelled.KeyTag[Wood, (UnitOfMeasure[Wood], Fraction[1, 1])], shapeless.::[(UnitOfMeasure[Sheep], Fraction[-1, 1]) with shapeless.labelled.KeyTag[Sheep, (UnitOfMeasure[Sheep], Fraction[-1, 1])], shapeless.HNil]]] = Quantity(
//   4.0
// )
val flocks = 8.0.flocks * tradingRate
// flocks: Quantity[Double, shapeless.::[(UnitOfMeasure[Wood], Fraction[1, 1]) with shapeless.labelled.KeyTag[Wood, (UnitOfMeasure[Wood], Fraction[1, 1])], shapeless.HNil]] = Quantity(
//   32.0
// )
flocks.show
// res0: String = "32.0 Log [W]"