выведите общий супертип на основе типов значения параметра и параметра функции

Если следующее компилируется, не нуждаясь в явном определении типа на this?

def prepList[B >: A](prefix: PlayList[B]) : PlayList[B] =
  prefix.foldr(this: PlayList[B])((node, suffix) => suffix.prepNode(node))

Мне кажется, что тип должен смочь к выведенному. Это - просто ограничение в компиляторе Scala или является там теоретической типом причиной, что это не может быть сделано? У меня действительно нет чувства еще для того, что тип Scala inferencer, как могут ожидать, обработает.

Работа через тот метод:

  • B >: A по определению
  • this имеет тип PlayList[A], который является подтипом PlayList[B] с тех пор B >: A и PlayList является ковариантным в A.
  • node имеет тип B, тип параметра prefix.
  • второй параметр к параметру функции f в foldr имеет тот же тип (объявленный B) как первый параметр к foldr.
  • Таким образом suffix имеет тот же тип как this, так в особенности это - a PlayList[A]. С тех пор B >: A, suffix.prepNode() берет a B.

Я хотел бы, чтобы компилятор видел это suffix.prepNode(node) законно где node имеет тип B. Это, кажется, может сделать это, только если я явно указываю тип на вызове foldr или на ссылке на this в том вызове.

Интересно, если я указываю явные типы на параметрах функции как (node: B, suffix: PlayList[B]), ошибка несоответствия типов все еще сгенерирована на параметре к вызову метода suffix.prepNode(node): "found: B, required: A"

Я использую Scala 2.8 RC6. Полный пример ниже, рассматриваемая строка является строкой 8.

sealed abstract class PlayList[+A] {
  import PlayList._
  def foldr[B](b: B)(f: (A, B) => B): B

  def prepNode[B >: A](b: B): PlayList[B] = nel(b, this)
  def prepList[B >: A](prefix: PlayList[B]): PlayList[B] =
    // need to specify type here explicitly
    prefix.foldr(this: PlayList[B])((node, suffix) => suffix.prepNode(node))

  override def toString = foldr("")((node, string) => node + "::" + string)
}

object PlayList {
  def nil[A]: PlayList[A] = Nil
  def nel[A](head: A, tail: PlayList[A]): PlayList[A] = Nel(head, tail)
  def nel[A](as: A*): PlayList[A] = as.foldRight(nil[A])((a, l) => l.prepNode(a))
}

case object Nil extends PlayList[Nothing] {
  def foldr[B](b: B)(f: (Nothing, B) => B) = b
}
case class Nel[+A](head: A, tail: PlayList[A]) extends PlayList[A] {
  def foldr[B](b: B)(f: (A, B) => B) = f(head, tail.foldr(b)(f))
}

Править: вторая попытка рассуждать через шаги компиляции

  • Переименование для ясности, foldr берет параметры типов (T)((U, T) => T). Мы пытаемся вывести значения типов U и T.
  • Существуют отношения между первым параметром к foldr и второй параметр к функции - они - то же самое, T. (В частичном ответе Daniel.)
  • Типы объектов, мы являемся передающими как те параметры, this: PlayList[A] и suffix: PlayList[B]
  • Так, с тех пор B >: A, самый определенный общий супер тип PlayList[B]; поэтому мы имеем T == PlayList[B]. Обратите внимание, что нам не нужны никакие отношения между U и T вывести это.

Это - то, где я застреваю:

  • Из сообщения ошибки компиляции inferencer ясно думает это node имеет тип B (то есть, U == B).
  • Я не вижу, как это получает к заключению это U == B не выводя его из параметра типа suffix. (scala компилятор может сделать это?)
  • Если тот шаг вывода - то, что происходит, то из этого следует, что U == B, и мы скомпилировали успешно. Таким образом, какой шаг пошел не так, как надо?

РЕДАКТИРОВАНИЕ 2: В переименовании foldr параметр вводит выше, я пропустил это U == A по определению это - параметр типа PlayList класс. Я думаю, что это все еще согласовывается с вышеупомянутыми шагами, хотя, так как мы называем его на экземпляре PlayList[B].

Таким образом на сайте вызова, T == PlayList[B] как наименее общий супертип нескольких вещей, и U == B по определению foldr на получателе. Это кажется достаточно кратким для сужения к нескольким опциям:

  • компилятор не может разрешить те несколько типов и вычислить верхнюю границу B
  • ошибка в получении от типа возврата PlayList[B] из foldr к типу параметра prepNode (скептически настроенный)
7
задан Joe Kearney 28 June 2010 в 17:56
поделиться

2 ответа

Я не эксперт по типам, но вот что происходит, когда я пытаюсь сделать вывод.

((узел, суффикс) => суффикс.prepNode (узел)) возвращает некоторый неизвестный тип PlayList [T] , где T расширяет A. Он передается в качестве аргумента функции foldr, которая возвращает тип переданной ему функции ( PlayList [T] , где T расширяет A). И это должен быть какой-то тип PlayList [B] .

Итак, я предполагаю, что this: PlayList [B] необходим, чтобы указать, что T и B связаны.

Может быть, вам нужно, чтобы PlayList был параметрическим в двух типах PlayList [+ A, B>: A] , поскольку у вас есть PrepNode и propList, которые, похоже, работают с тем же типом, который расширяет A?

Иными словами, ваше исходное определение класса могло быть определено следующим образом:

def prepNode[T >: A](b: T): PlayList[T]
def prepList[U >: A](prefix: PlayList[U]): PlayList[U]

Но вы использовали B в обоих случаях, и компилятор не знает, что T и U одинаковы.


Edit, вы можете поиграть с опцией -explaintypes и посмотреть, что делает компилятор в зависимости от подсказок типа, которые вы получаете. Вот результат выполнения команд объяснения и удаления : PlayList [B] (с 2.8.0.RC1):

$ scalac -explaintypes -d classes Infer.scala
found   : node.type (with underlying type B)
 required: A
    prefix.foldr(this)((node, suffix) => suffix.prepNode(node))
                                                         ^
node.type <: A?
  node.type <: Nothing?
    B <: Nothing?
      <notype> <: Nothing?
      false
      Any <: Nothing?
        <notype> <: Nothing?
        false
      false
    false
  false
  B <: A?
    B <: Nothing?
      <notype> <: Nothing?
      false
      Any <: Nothing?
        <notype> <: Nothing?
        false
      false
    false
    Any <: A?
      Any <: Nothing?
        <notype> <: Nothing?
        false
      false
    false
  false
false

Надеюсь, это поможет пролить свет.Может возникнуть вопрос о том, когда scalac может делать выводы, а когда не может делать выводы, было бы полезно.

3
ответ дан 7 December 2019 в 14:28
поделиться

Проблема в том, что foldr не указывает B>: A , поэтому, насколько foldr что касается его собственных типов A и B , нет никакой связи. Что касается foldr , суффикс и узел совершенно не связаны - даже если вы случайно передали ему связанные параметры.

1
ответ дан 7 December 2019 в 14:28
поделиться
Другие вопросы по тегам:

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