Границы типа Scala и дисперсия

Я пытаюсь лучше понять следующее поведение:

scala> class C[-A, +B <: A]
<console>:7: error: contravariant type A occurs in covariant position
                    in type >: Nothing <: A of type B
       class C[-A, +B <: A]
                    ^

Однако работает следующее:

scala> class C[-A, +B <% A]
defined class C

Я вижу, что могут быть проблемы из-за того, что дисперсия ограничивающих и ограниченных переменных противоположна, хотя мне не ясно, в чем заключается конкретная проблема. Я еще менее понимаю, почему изменение типа, связанного с представлением, делает все в порядке. В отсутствие применимых неявных преобразований я ожидаю, что два определения будут иметь в основном одинаковый эффект. Во всяком случае, я ожидаю, что вид обязательно предоставит больше возможностей для вреда.

В качестве предыстории я определяю классы, которые в некотором роде похожи на функции, и я хотел сделать что-то вроде

CompositeFunc[-A, +B <: C, -C, +D] (f1 : BaseFunc[A, B], f2 : BaseFunc[C, D]) 
  extends BaseFunc[A, D]

возможно

CompositeFunc[-A, +B <% C, -C, +D] (f1 : BaseFunc[A, B], f2 : BaseFunc[C, D]) 
  extends BaseFunc[A, D]

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


person Daniel Mahler    schedule 04.06.2013    source источник
comment
Интригует... Я потратил 1 час на поиск примера, где безопасность типов нарушается привязкой типа. Ничего не найдено :(   -  person gzm0    schedule 05.06.2013
comment
Кроме того, если бы был пример, который был несостоятельным с привязкой типа, трудно понять, как замена в привязке представления исправит это.   -  person Daniel Mahler    schedule 05.06.2013
comment
Да, в чем-то согласен. Но фундаментальное отличие состоит в том, что привязка представления всегда преобразуется в соответствии с типами, с которыми был создан класс, тогда как это не обязательно относится к привязке типа. (говорит моя интуиция по крайней мере...)   -  person gzm0    schedule 05.06.2013


Ответы (1)


Сначала легкий:

class C[-A, +B <% A]

Это эквивалентно

class C[-A, +B](implicit view: B => A)

Поскольку view публично не возвращается, он не находится в положении, которое ограничивало бы дисперсию A или B. Например.

class C[-A, +B](val view: B => A)  // error: B in contravariant position in view

Другими словами, C[-A, +B <% A] ничем не отличается от C[-A, +B] с точки зрения ограничений, аргумент представления ничего не меняет.


Случай верхней границы C[-A, +B <: A] Я не уверен. Спецификация языка Scala в §4.5 гласит:

Положение отклонения нижней границы объявления типа или параметра типа противоположно положению отклонения объявления типа или параметра.

Дисперсия B, по-видимому, не задействована, но обычно верхняя граница должна быть ковариантной:

trait C[-A, B <: A] // contravariant type A occurs in covariant position

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


Что касается составленной функции, почему бы просто не

class Composite[-A, B, +C](g: A => B, h: B => C) extends (A => C) {
  def apply(a: A) = h(g(a))
}

ИЗМЕНИТЬ. Например:

import collection.LinearSeq

def compose[A](g: Traversable[A] => IndexedSeq[A], h: Traversable[A] => LinearSeq[A]) =
  new Composite(g, h)
person 0__    schedule 04.06.2013
comment
Интересно, спасибо. Я не додумался попробовать trait C[-A, B <: A]. Я просто думал, что это должно быть противоположное отклонение. - person Daniel Mahler; 05.06.2013
comment
Да сочиняют, именно из-за дисперсии Function1 - person 0__; 05.06.2013
comment
класс CompositeFunc[-A, B, +C] не позволит вам составить f: BaseFunc(Traversable[A], IndexedSeq[A]) с g: BaseFunc(Traversable[A], LinearSeq[A]), даже если их композиции имеют смысл в обоих порядках. - person Daniel Mahler; 05.06.2013
comment
Да, @0__ , f и g должны составляться как функции, но мои классы на самом деле не расширяют Function, они просто подобны функциям. Вся проблема в том, что CompositeFunc(f, g) не набрал бы check в with CompositeFunc[-A, B, +C] из-за инвариантности B. Я был небрежен в своем первоначальном комментарии, сказав f: Traversable[A] => IndexedSeq[A], поэтому я переписал его. - person Daniel Mahler; 05.06.2013
comment
Жаль, что нет четкого объяснения по поводу C[-A, +B <: A] - person Freewind; 02.05.2014