Почему вывод типа не работает здесь?

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

class Minimal[T](x : T) {
  def doSomething = x
}

object Sugar {
  type S[T] = { def doSomething : T }
  def apply[T, X <: S[T]] (x: X) = x.doSomething
}

object Error {
  val a = new Minimal(4)
  Sugar(a) // error: inferred [Nothing, Minimal[Int]] does not fit the bounds of apply
  Sugar[Int, Minimal[Int]](a) // works as expected
}

Проблема в том, что компилятору удается выяснить внутренний параметр для Minimal (Int), но затем устанавливает другое вхождение T в Nothingчто явно не совпадает apply, Это определенно то же самое TТак как удаление первого параметра заставляет второй жаловаться, что T не определено.

Есть ли некоторая двусмысленность, которая означает, что компилятор не может вывести первый параметр, или это ошибка? Могу ли я обойти это изящно?

Дополнительная информация: этот код является простым примером попытки синтаксического сахара. Оригинальный код пытается сделать |(a)| означает модуль aгде а - вектор. очевидно |(a)| лучше, чем писать |[Float,Vector3[Float]](a)|, но, к сожалению, я не могу использовать unary_| чтобы сделать это проще.

Фактическая ошибка:

выводимые аргументы типа [Nothing,Minimal[Int]] не соответствуют границам параметров типа применения метода [T,X <: Sugar.S [T]]

2 ответа

Решение

Это не ошибка компилятора Scala, но, безусловно, это ограничение вывода типов в Scala. Компилятор хочет определить границу X, S[T], прежде чем решить для X, но в графе упоминается до сих пор переменная типа без ограничений T который поэтому исправляет в Nothing и исходит оттуда. Не возвращается T один раз X был полностью решен... в настоящее время вывод типа всегда происходит слева направо в этом случае.

Если ваш пример точно отражает вашу реальную ситуацию, то есть простое решение,

def apply[T](x : S[T]) = x.doSomething

Вот T будет выведено так, что Minimal соответствует S[T] напрямую, а не через посредническую переменную ограниченного типа.

Обновить

Решение Джошуа также позволяет избежать проблемы определения типа T, но совершенно по-другому.

def apply[T, X <% S[T]](x : X) = x.doSomething

Desugars к,

def apply[T, X](x : X)(implicit conv : X => S[T]) = x.doSomething

Переменные типа T а также X Теперь можно решить самостоятельно (потому что T больше не упоминается в Xсвязан). Это означает, что X выводится как Minimal немедленно и T решается как часть неявного поиска значения типа X => S[T] удовлетворить неявный аргумент conv, conforms в scala.Predef manufactures values of this form, and in context will guarantee that given an argument of type Minimal, T will be inferred as Int. You could view this as an instance of functional dependencies at work in Scala.

Есть некоторые странности с границами для структурных типов, попробуйте вместо этого использовать представление, связанное с S[T].

def apply[T, X <% S[T]] (x: X) = x.doSomething работает отлично.

Другие вопросы по тегам