Множественные нижние границы типов в Scala

Я заметил, что tuple.productIterator всегда возвращает Iterator[Any], и задался вопросом, нельзя ли установить несколько нижних границ (так что это может быть итератор самого низкого общего супертипа).

Я пробовал и искал немного, но нашел только это Вопрос по множеству оценок сверху.

Это мой тест на определение типа итератора:

def f[A,B](a:A, b:B) = List(a,b)
// return type is List[Any]

def f[A,B, T >: A "and" T >: B](a:A, b:B) = List[T](a,b)
// doesn't compile, but
//  f(1, true) should give a List[AnyVal] and
//  f("x", "y") a List[String]

Это ограничение JVM?


Изменить: Вот немного более крупный пример, который, похоже, не может быть решен с использованием подхода IttayD, когда T должен быть определен в методе:

class Foo[A, B](a: A, b: B) {
  def f[T >: A] = List[T](a) // works
  def g[T >: A "and" T >: B] = List[T](a) // doesn't work
}

person kassens    schedule 24.05.2011    source источник


Ответы (2)


В простом случае, когда A и B связаны компилятором одновременно с T, Ответ IttayD работает нормально:

def f[T, A <: T,B <: T](a:A, b:B) = List[T](a,b)

Когда A и B уже связаны, как в вашем примере class Foo[A, B], вам нужно ввести временные фиктивные переменные, чтобы компилятор выполнял эту работу:

class Foo[A, B](a: A, b: B) {
  def g[T, A1 >: A <: T, B1 >: B <: T] = List[T](a: A1, b: B1)
}

(Для ясности: A1 >: A <: T означает, что тип A1 должен быть супертипом A и подтипом T, а не то, что A является подтипом как A1, так и T.)

A1 и B1 здесь с единственной целью - вывести правильный тип для T. Если компилятор должен вывести их, они разрешат A1 = A и B1 = B, а затем T как наиболее конкретный тип, который является суперклассом как A, так и B.

Однако компилятор не понимает, что из-за транзитивности у нас есть как T >: A, так и T >: B, что прямо следует из ограничений относительно A1 и B1. Нам нужно помочь с описанием типов.

Теперь Product#productIterator не может использовать этот метод, поскольку он определен в месте, где мы даже не знаем A и B, или, действительно, сколько параметров типа имеется в конкретном подклассе.

person Jean-Philippe Pellet    schedule 25.05.2011

Похоже, вам нужен HList: http://apocalisp.wordpress.com/2010/07/06/type-level-programming-in-scala-part-6a-heterogen-list%C2%A0basics/

Чтобы ответить на конкретный вопрос:

scala> def f[T, A <: T,B <: T](a:A, b:B) = List[T](a,b)
f: [T, A <: T, B <: T](a: A, b: B)List[T]

scala> f(1, true)
res0: List[AnyVal] = List(1, true)

scala> f("x", "y")
res1: List[java.lang.String] = List(x, y)
person IttayD    schedule 25.05.2011
comment
Это почти эквивалентно простому def f[T](a:T, b:T) = List[T](a,b) - person Jean-Philippe Pellet; 25.05.2011
comment
f (1,2.0) приведет к List [Double] = List (1.0, 2.0) - person IttayD; 25.05.2011
comment
Что, если A и B были определены во внешней области? Нужно ли мне переместить определение T также во внешнюю область видимости? (@IttayD исправил пример) - person kassens; 25.05.2011
comment
@IttayD Ваше обновление опасно: посмотрите на возвращаемый тип List[Int with Double]… Забавный тип. Вы заставляете компилятор поверить, что это список элементов, которые являются как внутренними, так и двойными. Попробуйте это и получите нежелательный ClassCastException: val res = (new Foo(1, "hi")).g; res.head.size - person Jean-Philippe Pellet; 25.05.2011
comment
Тот факт, что приписывание типов не работает, указывает на то, что компилятору это не нравится. - person Jean-Philippe Pellet; 25.05.2011
comment
@IttayD Поищите в моем ответе решение без HLists. - person Jean-Philippe Pellet; 25.05.2011