Как использовать класс зависимого от пути типа - PullRequest
0 голосов
/ 05 апреля 2020

Я пытаюсь использовать класс зависимого от типа в методе, как показано ниже:

@typeclass trait Identifiable[M] {
  type K
  def identify(id: M): K
}

object Identifiable {
  type Aux[M, K0] = Identifiable[M] { type K = K0 }
  implicit def identifiableTuple[K1, K2](
      implicit
      a: Identifiable[K1],
      b: Identifiable[K2]
  ): Identifiable.Aux[(K1, K2), (a.K, b.K)] = new Identifiable[(K1, K2)] {
    type K = (a.K, b.K)
    override def identify(id: (K1, K2)): K = {
      val k1 = a.identify(id._1)
      val k2 = b.identify(id._2)
      (k1, k2)
    }
  }

Однако, когда я пытаюсь использовать его, как показано ниже, неявные параметры не разрешаются

def a[K: Identifiable](key:K) = { 
case k => 
 val keyString: String = the[Identifiable.Aux[K, String]].identify(key) 
case (k1,k2) => 
 val keyString: (String,String) = the[Identifiable.Aux[K, (String, String)]].identify(key) }

Ответы [ 3 ]

2 голосов
/ 05 апреля 2020

Вы требуете неявного с зависимым от пути типом в ограничении типа, но затем вызываете неявный с этим типом, фиксированным к чему-либо.

Для того, чтобы это работало, компилятор должен был бы доказать, что зависимый тип в Identifiable является равно K, что в текущем коде не может быть сделано.

Вы можете попробовать:

  • использовать одинаковое соглашение в обоих местах (либо с Aux, либо с обоим с зависимым типом)
  • доказать, что зависимый тип равен K с неявным доказательством ev: identifiable.K =:= K
1 голос
/ 05 апреля 2020

Но почему вы ожидаете, что они совпадут? В ветке case k => существует неявный тип Identifiable[K], но нет никаких оснований ожидать, что это будет Identifiable[K] { type K = String }, который вы пытаетесь запросить с помощью the. Или Identifiable[K] { type K = (String, String) } в другой ветке. (Обратите внимание, что у вас есть два разных значения для K, что может немного сбивать с толку.)

[Из комментария] case class K1 (value: String); case case K2 (значение: String) Я ожидаю: a (K1) => String и a ((K1, K2)) => (String, String)

Наиболее разумный вариант, близкий к тому, что Вы хотите, кажется, просто

def a[A](key:A)(implicit ev: Identifiable[A]): ev.K = ev.identify(key)
1 голос
/ 05 апреля 2020

Шаблон (k1,k2) должен быть перед неограниченным шаблоном k, иначе все будет go до k и ничего до (k1,k2).

Сопоставление с шаблоном в основном работает во время выполнения и вводит классы / имплициты в основном работают во время компиляции. Поскольку вы начали работать с классами типов (и, более того, с классами типов с типом-членом), похоже, что вы хотите иметь некоторые вычисления для типов, то есть некоторые вычисления во время компиляции.

Logi c ветвление во время выполнения соответствует для сопоставления с образцом. Логическое c ветвление во время компиляции соответствует классу типа и несколько последствий, определяющих экземпляры класса типа.

Попробуйте сделать a() классом типа

trait A[K] {
  def apply(key: K): Unit
}

object A {
  implicit def tupleA[K](implicit identifiable: Identifiable.Aux[K, (String, String)]): A[K] = new A[K] {
    override def apply(key: K): Unit = key match {
      case (k1, k2) =>
        val keyString: (String, String) = identifiable.identify(key)
        ()
    }
  }

  implicit def defaultA[K](implicit identifiable: Identifiable.Aux[K, String]): A[K] = new A[K] {
    override def apply(key: K): Unit = {
      val keyString: String = identifiable.identify(key)
      ()
    }
  }
}

def a[K](key: K)(implicit aInstance: A[K]) = aInstance(key)

Вы должны написать несколько примеров того, как вы планируете применить свой a(). На какие входы вы рассчитываете, какие выходы. Что должно компилироваться, что не должно компилироваться?

Обычно параметры типа (например, M для Identifiable[M]) похожи на входы, а члены типа (например, K для Identifiable[M] { type K }) похожи на выходные данные для типа- расчеты уровня. Поэтому для Identifiable похоже, что тип K будет выбран в зависимости от типа M. Это правильно? Пожалуйста, подумайте о вашей логике c (что такое входы, какие выходы). В a() вы, похоже, начинаете что-то делать, основываясь на типе K.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...