Общий тип контейнера (более высокий тип) для «карты» в Scala - PullRequest
0 голосов
/ 22 сентября 2018

Я пытаюсь определить класс дел, параметризованный с типом контейнера (более высокий тип).Этот тип контейнера может быть любым, если для него определен метод карты.

Я хотел бы добиться этого результата, предложенного в следующем коде:

import scala.language.higherKinds

case class Test[A, C[A]](init: A, trans: Map[A,C[A]]) {
  def convert[B](conv: A => B): Test[B, C[B]] = {
    val _init = conv(init)
    val _trans = trans map {case (k,v) => (conv(k) -> (v map {x => conv(x)})}
    Test(_init, _trans)
  }
}

проблема заключается в v map {x => conv(x)} часть кода.Поскольку для C[A] граница не была определена, она, очевидно, не компилируется.

Дело в том, что этот тип контейнера может быть Id (стиль Scalaz, но с map вместо |>) и Option, или коллекцию (Seq, Set, List и т. д.)

Можно ли сообщить компилятору scala, что тип контейнера должен иметь map метод?

1 Ответ

0 голосов
/ 22 сентября 2018

Лучший способ достичь желаемого - использовать класс типа Functor .Например, вот пример использования Кошки .
(Вы можете сделать то же самое, используя Scalaz ) .

import scala.language.higherKinds

import cats.Functor
import cats.syntax.functor.toFunctorOps

final case class Test[A, C[_]](init: A, trans: Map[A,C[A]])(implicit CFunctor: Functor[C]) {
  def convert[B](conv: A => B): Test[B, C] = {
    val _init = conv(init)
    val _trans = trans map { case (k,v) => conv(k) -> v.map(x => conv(x)) }
    Test(_init, _trans)
  }
}

Однако, если по какой-то причине вы не можете или не хотите использовать Cats / Scalaz, вы можете попробовать Структурные типы .

import scala.language.higherKinds
import scala.language.reflectiveCalls

final case class Test[A, C[A] <: { def map[B](f: A => B): C[B]}](init: A, trans: Map[A,C[A]]){
  def convert[B](conv: A => B): Test[B, C] = {
    val _init = conv(init)
    val _trans = trans map { case (k,v) => conv(k) -> v.map(x => conv(x)) }
    Test(_init, _trans)
  }
}

Тем не менее, обратите вниманиечто последний будет работать для Option, но не будет работать для List, просто потому, что метод map в List получает неявный CanBuildFrom, и по этой причине он не равен желаемому.

...