Skip to content

Instantly share code, notes, and snippets.

@johnynek
Last active March 31, 2020 20:49
Show Gist options
  • Save johnynek/2432e2e61221cbf9e56fc4d784c3fac7 to your computer and use it in GitHub Desktop.
Save johnynek/2432e2e61221cbf9e56fc4d784c3fac7 to your computer and use it in GitHub Desktop.
using literal types in scala 2.13 to track the half-life of an exponential decay
case class Timestamp(epochMillis: Long)
case class Decay[H <: Double](scaledTime: Double, value: Double) {
def timestampDouble(implicit v: ValueOf[H]): Double =
scaledTime * v.value
def timestamp(implicit v: ValueOf[H]): Timestamp =
Timestamp(timestampDouble.toLong)
def combine(that: Decay[H]): Decay[H] =
if (scaledTime > that.scaledTime) that.combine(this)
else {
// we know scaledTime <= that.scaledTime
val decayThis = math.exp(scaledTime - that.scaledTime) * value
if (decayThis == 0.0) that
else Decay[H](that.scaledTime, that.value + decayThis)
}
}
object Decay {
def build[H <: Double: ValueOf, N: Numeric](time: Timestamp, n: N): Decay[H] =
Decay(time.epochMillis.toDouble / valueOf[H], implicitly[Numeric[N]].toDouble(n))
implicit def monoidForDecay[H <: Double]: Monoid[Decay[H]] =
new Monoid[Decay[H]] {
val empty = Decay[H](Double.NegativeInfinity, 0.0)
def combine(l: Decay[H], r: Decay[H]): Decay[H] = l.combine(r)
}
}
@deanwampler
Copy link

That works better (and makes more sense ;) Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment