1

Location のサブクラスの List を受け取るジェネリック ケース クラス Route があります。ただし、次のメソッドでは、への呼び出しで型の不一致が発生しますdistance expected: head.T, actual: T

case class Route[T <: Location](route: List[T]) {
  def measureDistance: Double = {
    def measure(head: T, tail: List[T], acc: Double = 0.0): Double = tail match {
      case Nil => acc
      case h :: t => measure(h, t, head.distance(h) + acc)
    }
    if (route.isEmpty) 0.0
    else measure(route.head, route.tail)
  }
}

基本的な抽象 Location クラスは次のとおりです。

abstract class Location(val name: String) {

type T <: Location

def distance(that: T): Double
}

head と h は両方とも同じリストから来てrouteいるので、なぜこれらが同じ型ではないのか理解できません。

4

3 に答える 3

3

この場合、F-bounded polymorphism が必要なように見えます。

abstract class Location[L <: Location[L]](val name: String) {
  def distance(that: L): Double
}

case class Route[T <: Location[T]](route: List[T]) {
  def measureDistance: Double = {
    def measure(head: T, tail: List[T], acc: Double = 0.0): Double = tail match {
      case Nil => acc
      case h :: t => measure(h, t, head.distance(h) + acc)
    }
    if (route.isEmpty) 0.0
    else measure(route.head, route.tail)
  }
}

ただし、Metric代わりに -typeclassの使用を検討することもできます。

trait Metric[L] {
  def dist(a: L, b: L): Double
}

case class Route[T: Metric](route: List[T]) {
  def measureDistance: Double = {
    def measure(head: T, tail: List[T], acc: Double = 0.0): Double = tail match {
      case Nil => acc
      case h :: t => measure(h, t, implicitly[Metric[T]].dist(head, h) + acc)
    }
    if (route.isEmpty) 0.0
    else measure(route.head, route.tail)
  }
}

後者の解決策は、(Double, Double)から継承していなくても、など、より多くの型に適用できLocationます。

再び型クラスの解決策を次に示しますが、回避する少し洗練された Cats スタイルの構文を使用しますimplicitly

trait Metric[L] {
  def dist(a: L, b: L): Double
}

object Metric {
  def apply[T](implicit m: Metric[T]): Metric[T] = m
}

case class Route[T: Metric](route: List[T]) {
  def measureDistance: Double = {
    def measure(head: T, tail: List[T], acc: Double = 0.0): Double = tail match {
      case Nil => acc
      case h :: t => measure(h, t, Metric[T].dist(head, h) + acc)
    }
    if (route.isEmpty) 0.0
    else measure(route.head, route.tail)
  }
}
于 2018-06-08T09:53:15.007 に答える