Как отобразить Hlist объектов, которые расширяют общие черты? - PullRequest
6 голосов
/ 14 июня 2019

У меня есть черта и объекты, которые его расширяют.

trait Common[K] {
  def name: String
  def encode(k: K): String = name + k.toString
}

object A extends Common[Int] {
  override def name: String = "a"
}

object B extends Common[Int] {
  override def name: String = "b"
}

object C extends Common[Int] {
  override def name: String = "c"
}

Я хочу создать список этих объектов и отобразить его:

val hl = A :: B :: C :: HNil
val result: List[Int => String] = hl.map(EncodePoly).toList

И различные попытки реализовать Polyfunction:

object EncodePoly extends Poly1 {
  implicit def indCase[K]: Case.Aux[Common[K], K => String] = at[Common[K]] {
    common => k =>
      common.encode(k)
  }
}

object EncodePoly extends Poly1 {
  implicit def indCase[K, C <: Common[K]]: Case.Aux[C, K => String] = at[C] {
    common => k =>
      common.encode(k)
  }
}

Компилятор сообщает мне:

Ошибка: (45, 43) не удалось найти неявное значение для преобразователя параметров: shapeless.ops.hlist.Mapper [com.test.EncodePoly.type, com.test.A.type :: com.test.B.type :: com.test.C.type :: shapeless.HNil] val результат: List [Int => String] = hl.map (EncodePoly) .toList

Я также пытался использовать зависимые типы для общей черты вместо параметра типа.Ничто не похоже на работу.Как мне работать с списком объектов?

1 Ответ

5 голосов
/ 14 июня 2019

Ваш второй EncodePoly близок, но компилятор недостаточно умен, чтобы сделать вывод, что K должно быть Int, а затем C должно быть синглтонного типа. Вы можете вывести вывод типа, кодируя отношение подтипа, используя <:< вместо <::

trait Common[K] {
  def name: String
  def encode(k: K): String = name + k.toString
}

object A extends Common[Int] {
  override def name: String = "a"
}

object B extends Common[Int] {
  override def name: String = "b"
}

object C extends Common[Int] {
  override def name: String = "c"
}

import shapeless.{ ::, HNil, Poly1 }

object EncodePoly extends Poly1 {
  implicit def indCase[K, C](implicit ev: C <:< Common[K]): Case.Aux[C, K => String] = at[C] {
    common => k => common.encode(k)
  }
}

А потом:

scala> val hl = A :: B :: C :: HNil
hl: A.type :: B.type :: C.type :: shapeless.HNil = A$@3f044518 :: B$@282b7aad :: C$@7c130749 :: HNil

scala> val result: List[Int => String] = hl.map(EncodePoly).toList
result: List[Int => String] = List(EncodePoly$$$Lambda$5555/1493211716@7c987ea3, EncodePoly$$$Lambda$5555/1493211716@10be689, EncodePoly$$$Lambda$5555/1493211716@5dd3c2f2)

Если вы можете исправить K в Int в своем определении EncodePoly, это также сработает.

...