Reputation: 10716
The function reduceTo gets a type parameter indicating the kind of time series that should be returned, but the function splitInto requires a Period value. I want to make sure they are coherent so you can't do this:
reduceTo[MonthlySeries](period=Weekly) // not ok
reduceTo[MonthlySeries](period=Monthly) // but this is ok
reduceTo[MonthlySeries] // even better, derive the period from the type param
The type parameter should be sufficient but I can't seem to get the Period information I need from the parametrised type. Here's the simplified code:
sealed trait Period
case class Daily extends Period
case class Monthly extends Period
sealed abstract class TimeSeries {
type T
}
case class DailySeries extends TimeSeries {
type T = Daily.type
}
case class MonthlySeries extends TimeSeries {
type T = Monthly.type
}
implicit class DailySeriesOps(lhs: DailySeries) {
def reduceTo[G: TimeSeries](period: Period):G {
// instead of sending the period in, how do I get
// the period value from the type G?
// Or at least constrain the period value?
val s = splitInto(period, lhs)
val reduced : G = ...
// this is ugly
assert(reduced.period == period, s"Reducing to $period but timeseries is ${reduced.period}")
}
}
Initially I thought path dependent types would help so something like
def reduceTo[G: TimeSeries](period: G.T)
but that would require, from what I understand, that Daily would be a class defined inside DailySeries, which since it's used in other contexts is not ideal.
Another idea, which doesn't work, would be not to send the period parameter in but get the value from G, but since its instance doesn't exist yet, it doesn't work
def reduceTo... = {
val period = G.T
...
}
[Update]
Also tried
def reduceTo[G : TimeSeries](period: TimeSeries#T: G = {
val ts = reduce[F](period.asInstanceOf[GroupedPeriod], lhs)
But then this fails to compile with a type mismatch on reduceTo calls:
type mismatch;
[error] found : com.example.metrics.Periods.Monthly.type
[error] required: com.example.metrics.calculations.TimeSeries#T
Any ideas?
Upvotes: 3
Views: 153
Reputation: 1153
According to your comment if GroupedSeries has type T
field you could use period: G#T
, or if don't you would need to add additional generic parameter and use something like:
def reduceTo[G <: GroupedSeries[_], T <: TimeSeries](period: T#T): G = {
//Your code
}
And with this my compiler is saying:
DailySeriesOps().reduceTo[DailySeries,DailySeries](Monthly) // I don't compile that
DailySeriesOps().reduceTo[DailySeries,DailySeries](Daily) // that i will
DailySeriesOps().reduceTo[MonthlySeries,MonthlySeries](Monthly) // that i will too
DailySeriesOps().reduceTo[MonthlySeries,MonthlySeries](Daily) // and not this one
But your question is not easy reproducible, so I don't know if this can answer your question, I hope it helps
Upvotes: 1