Вопрос по alias, variance, scala – Отклонение аннотации в псевдонимах типа

13

Недавно я заметил, что аннотации к дисперсиям могут использоваться в псевдонимах типов. Вот пример изPredef:

<code>type Function[-A, +B] = Function1[A, B]
</code>

И я начал думать, где это можно использовать. Очевидно, что вы не можете изменить дисперсию на противоположную или создать инвариантный тип, который будет вести себя как ко- или контравариантный. Компилятор выдаст ошибку, вот так

<code>scala> type BrokenFunc[+T, -R] = Function1[T, R]
<console>:7: error: covariant type T occurs in contravariant position in type 
  [+T, -R]T => R of type BrokenFunc
</code>

Но вы можете заставить некоторый вариантный тип вести себя как инвариант (по крайней мере, компилятор с этим не поспорит). Итак, я попытался сделать инвариантную версиюList

<code>scala> type InvList[T] = List[T]
defined type alias InvList
</code>

Но этот новый инвариантList по-прежнему ведет себя так же, как и оригинальная ковариантная версия:

<code>scala> val l: InvList[String] = List("foo")
l: InvList[String] = List(foo)

scala> val anyList: InvList[Any] = l
anyList: InvList[Any] = List(foo)
</code>

Итак, чего мне не хватает? Какова цель аннотаций дисперсии в псевдонимах типа? Можете ли вы привести пример псевдонима типа с аннотациями отклонений, которые будут отличаться от исходного типа.

Ваш Ответ

2   ответа
8

я не знаю наверняка, но я собираюсь предложить возможное объяснение.

Псевдонимы типа в Scala довольно «слабые»; они не полностью создают новые типы, просто новые способы записи старых типов (и новых зависимых от пути типов); это означает, что если вы определите

type InvList[T] = List[T]

и писатьInvList[T], это так же, как если бы вы написалиList[T]; вот почемуInvList[Int] <: InvList[Any]потому что, переписано, это простоList[Int] <: List[Any], На самом деле я не совсем уверен, насколько "слаб" Псевдонимы типа Scala ... они немного сильнее, чем у Haskell из-за зависимых от пути типов, но они слабее, чем объявления классов. Может быть, кто-то еще может объяснить дальше.

, почему Scala позволяет вам размещать аннотации отклонений, если он просто игнорирует их и переписывает тип в любом случае? Это для членов типа. Это так, что вы можете сказать,

trait A { type F[+T] }

и требуют, чтобы реализации соответствовали+T дисперсия, так что вы позволяете

trait B extends A { type F[+T] = List[T] }

но нет

trait C extends A { type F[T] = Function[T,T] }

Или, как в этом предложении изScala Language Spec S4.3.

A type constructor declaration imposes additional restrictions on the concrete types for which t may stand. Besides the bounds L and U , the type parameter clause may impose higher-order bounds and variances, as governed by the conformance of type constructors (§3.5.2).

@ThiporKong по пункту 1, я попробовал его в REPL, и он работает хорошо, так что я думаю, что это должно быть хорошо. По пункту 2 вы «правы», «слабые»; может быть вводящим в заблуждение словом, но это слово, которое я слышал, использовалось для этого ранее (например, typedef в C, псевдонимы типов в Haskell). Слабое не значит плохое. Но есть ли лучшее слово, которое я мог бы использовать?
@ Оуэн, да, похоже, псевдонимы типов просто переписывают старые типы, а компилятор только гарантирует, что вы не пишете что-то сумасшедшее. Теперь, с вашим примером, это имеет смысл для меня. Благодарю. 4e6
Число рейнольдса Функция - да, конечно, вы правы. Не знаю, что я видел.
Я также не сказал бы, что псевдонимы типа являются «слабыми», потому что они являются тем, чем они являются (псевдонимы). Я думаю, что это отличная функция, и она совершенно отсутствует в Java. Как часто я хотел иметь более короткое имя для таких вещей, как Map & lt; List & lt; Integer & gt;, Map & lt; String, Double & gt; & gt; без определения отдельного класса со всеми необходимыми последствиями.
2

Domain), неизменность будет соблюдаться. Если абстрактный тип определен так, чтобы иметь более смягченную дисперсию, это учитывается после того, как он известен (как вDomainImpl):

trait Domain {
  type InvList[T]

  val xi: InvList[Int]
  private val xa: InvList[Any] = xi // won't compile
}

class DomainImpl extends Domain {
  type InvList[T] = List[T]

  val xi: InvList[Int] = List(1)
  private val xa: InvList[Any] = xi // will compile
}

Похожие вопросы