Типы Scala и компиляция

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

import shapeless.tag
import shapeless.tag.@@

object Typeplay {
  trait StringTrait
  type MyString = String @@ StringTrait

  case class StringClass(mps: MyString)
  val stringClass = StringClass(tag[StringTrait]("test"))
}

И этот код не будет компилироваться. Компилятор Scala жалуется на последнюю строку кода, говорящую:

[error]  found   : String("test")
[error]  required: shapeless.tag.Tagged[in.bharathwrites.Typeplay.StringTrait] with String
[error]   val stringClass = StringClass(tag[StringTrait]("test"))

Я не мог понять, что я делаю не так. Поэтому я внес небольшое изменение в свой код -

import shapeless.tag
import shapeless.tag.@@

object Typeplay {
  trait StringTrait
  type MyString = String @@ StringTrait

  case class StringClass(mps: MyString)

  val stringTag = tag[StringTrait]("test")
  val stringClass = StringClass(stringTag)
}

Что в основном просто использует явную переменную для тегов. И этот код компилируется!!

Как это может быть? Почему первая программа не компилируется, а вторая компилируется?


person Bharadwaj    schedule 11.05.2016    source источник


Ответы (1)


Кажется, что в этом случае псевдоним типа запутывает вывод типа. Если вы предоставляете явные типы методу tag, все работает нормально:

StringClass(tag[StringTrait][String]("test"))

or

StringClass(tag[StringTrait]("test"):String @@ StringTrait)

или если вы объявите параметр StringClass напрямую:

case class StringClass(mps: String @@ StringTrait)

StringClass(tag[StringTrait]("test"))

Видимо ограничение компилятора scala.


UPD. Честно говоря, я не могу сказать, какое именно ограничение вывода типа вы здесь натолкнулись. Мои поиски релевантных открытых ошибок оказались безрезультатными.

По поводу первого примера. Все становится понятно, если посмотреть на реализацию tag:

object tag {
  def apply[U] = new Tagger[U]

  trait Tagged[U]
  type @@[+T, U] = T with Tagged[U]

  class Tagger[U] {
    def apply[T](t : T) : T @@ U = t.asInstanceOf[T @@ U]
  }
}

Итак, когда вы делаете это:

tag[StringTrait][String]("test")

Вы в основном делаете это:

tag.apply[StringTrait].apply[String]("test")
person Aivean    schedule 11.05.2016
comment
Не могли бы вы пролить свет на то, что это за ограничение. Кроме того, я озадачен тем, как значение может быть приведено к более чем 1 типу, как вы сделали в своем первом предложении. Это работает, но я не понимаю, как. Я попробовал небольшую программу, чтобы увидеть, работает ли это во всех сценариях, и это не сработало. - person Bharadwaj; 13.05.2016