Предоставить неявное подтверждение псевдонима типа в Scala - PullRequest
0 голосов
/ 06 сентября 2018

Есть ли способ заставить компилятор как-то учитывать псевдонимы типов при поиске неявных свидетельств?

Вот пример проблемы, которую я пытаюсь решить:

// Third party library
class Foo[T, P]
class FooOps[FTP, T] {
  def apply[F[_, _], P](t: T)(implicit ev: F[T, P] =:= FTP): FTP = ???
}

type StringFoo = Foo[String, Boolean]
object StringFoo extends FooOps[StringFoo, String]

StringFoo("hello")

// Attempt to wrap the third party type but have the same ops
class WrappedFoo[FTP](val foo: FTP)
object WrappedFoo {
  type F[T, P] = WrappedFoo[Foo[T, P]]
}

type WrappedStringFoo = WrappedFoo[StringFoo]
object WrappedStringFoo extends FooOps[WrappedStringFoo, String]

WrappedStringFoo("hello") // Cannot prove that F[String, P] =:= WrappedStringFoo
WrappedStringFoo[WrappedFoo.F, Boolean]("hello”) // This works

Я не совсем понимаю, как компилятор выводит типы в:

StringFoo("hello")

Использует ли он каким-либо образом доступные значения для выбора значения для F[_, _]? Я всегда думал, что сначала нужно определиться с типами.

Однако это работает для StringFoo, это не работает для WrappedStringFoo. Вероятно, так как количество параметров типа отличается.

Как я могу получить:

WrappedStringFoo("hello")

компилировать без явного указания типов?

1 Ответ

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

Попробуйте добавить необходимое неявное в область действия:

import scala.language.higherKinds

class Foo[T, P]
class FooOps[FTP, T] {
  def apply[F[_, _], P](t: T)(implicit ev: F[T, P] =:= FTP): FTP = ???
}

type StringFoo = Foo[String, Boolean]
object StringFoo extends FooOps[StringFoo, String]

class WrappedFoo[FTP](val foo: FTP)
object WrappedFoo {
  type F[T, P] = WrappedFoo[Foo[T, P]]

  //implicit val ev0: WrappedFoo.F[String, Boolean] =:= WrappedStringFoo = ???
  implicit val ev0: WrappedFoo.F[String, Boolean] =:= WrappedStringFoo = 
    null.asInstanceOf[WrappedFoo.F[String, Boolean] =:= WrappedStringFoo]
}

type WrappedStringFoo = WrappedFoo[StringFoo]
object WrappedStringFoo extends FooOps[WrappedStringFoo, String]

WrappedStringFoo("hello") 

Когда вы делаете StringFoo("hello"), компилятор решает уравнение F[String, P] = Foo[String, Boolean], и он достаточно умен, чтобы вывести P = Boolean, F = Foo. Но когда вы делаете WrappedStringFoo("hello"), компилятор должен решить уравнение F[String, P] = WrappedFoo[Foo[String, Boolean]], а используемые им алгоритмы недостаточно умны, чтобы вывести P = Boolean, F = ({ type λ[A, B] = WrappedFoo[Foo[A, B]] })#λ, то есть WrappedFoo.F (и, возможно, такие уравнения не могут быть решены вообще, если они достаточно продвинуты). Таким образом, вы должны предоставить подсказку. Либо указав параметры типа явно, либо предоставив необходимые неявные доказательства.

Разрешение имплицитов и вывод типа влияют друг на друга. Вы можете прочитать раздел 4.4.3 диссертации Евгения Бурмако .

...