I agree with Luciano that your HalfInterval
is slightly out of the box.
But since engineers like things out-of-the-box, where you have to assemble it before you can play with it, here's another angle.
Your HalfInterval
says, give me an Interval
factory, and I'll hand you evidence about the Interval
that is required.
Here I've changed the param type to Any, but in this case it could be Either[Int, Time]
, where the int means minutes in the future and the time is an end time. More generally, it could be a marker trait, more safe than Any.
To answer your question, Where does the start time come from?, you see that the closure in from
captures the start
.
import scala.language.implicitConversions
import util._
case class Time(hour: Int, minute: Int) {
def +(delta: Int) = Time(hour, minute + delta) // TODO overflow minutes
}
case class Interval(start: Time, end: Time)
object Interval {
case class HalfInterval(half: Any => Interval) {
def to(time: Time): Interval = half(time)
def forMinutes(minutes: Int): Interval = half(minutes)
}
def from(start: Time) = HalfInterval((arg: Any) => arg match {
case delta: Int => Interval(start, start + delta)
case end: Time => Interval(start, end)
case _ => throw new IllegalArgumentException
})
}
object Time {
def apply(hourMinute: String): Time = {
val tries = hourMinute.split(":").map(s => Try(s.toInt))
tries match {
case Array(Success(hour), Success(minute)) => Time(hour, minute)
case _ => throw new IllegalArgumentException
}
}
implicit def stringToTime(hourMinute: String) = Time(hourMinute)
}
object Test extends App {
import Interval._
assert(from("20:30").to("20:50") == Interval("20:30", "20:50") )
assert(from("20:30").forMinutes(10) == from("20:30").to("20:40"))
}
An inverted formulation, where the signatures are stranger but the code makes more sense:
object Interval {
case class HalfInterval(f: (Time=>Time) => Interval) {
def to(end: Time): Interval = f(_ => end)
def forMinutes(minutes: Int): Interval = f(_ + minutes)
}
def from(start: Time) = HalfInterval((end: Time=>Time) => Interval(start, end(start)))
}
Both to
and forMinutes
know how to make an end time from a start time.
This makes it easier to add e.g. until(end: Time)
, forSeconds(secs: Int)
.