简体   繁体   English

如何在scala中通过类型参数的类型成员约束参数?

[英]How to constrain argument by type member of type parameter in scala?

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. 函数reduceTo获取一个类型参数,指示应返回的时间序列的类型,但函数splitInto需要一个Period值。 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. 类型参数应该足够了,但我似乎无法从参数化类型中获取我需要的Period信息。 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. 但是根据我的理解,这将需要每日将在DailySeries中定义的类,因为它在其他环境中使用并不理想。

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 另一个不起作用的想法是不发送period参数但是从G获取值,但由于它的实例尚不存在,它不起作用

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: 但是,这在reduceTo调用上的类型不匹配时无法编译:

type mismatch;
[error]  found   : com.example.metrics.Periods.Monthly.type
[error]  required: com.example.metrics.calculations.TimeSeries#T

Any ideas? 有任何想法吗?

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: 根据您的评论,如果GroupedSeries具有type T字段,您可以使用period: G#T ,或者如果不是,则需要添加其他通用参数并使用如下内容:

  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 但你的问题不容易再现,所以我不知道这是否可以回答你的问题,我希望它有所帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM