2012-04-27 6 views
6

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

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 - вектор. Очевидно, |(a)| лучше, чем писать |[Float,Vector3[Float]](a)|, но, к сожалению, я не могу использовать unary_|, чтобы сделать это проще.

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

inferred type arguments [Nothing,Minimal[Int]] do not conform to method apply's type parameter bounds [T,X <: Sugar.S[T]]

ответ

9

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

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

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

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

Update

решение Джошуа также устраняет проблему выводя типа 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 производит значения этой формы, и в контексте гарантирует, что с учетом аргумента типа Minimal, T будет выведено как Int. Вы можете просмотреть это как пример functional dependencies на работе в Scala.

+0

Да, это решение отлично работает в моем случае. Он также чище, чем решение Джошуа (извините, Джошуа!). Можете ли вы объяснить, почему работает решение Джошуа? – Dylan

+0

Ответ обновлен, чтобы дать объяснение, почему решение Джошуа также работает. –

4

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

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

+1

Отлично, это работает, но, конечно, не должно быть разницы между подходами? Взгляд в этом случае - это просто литье в суперкласс, не так ли? Означает ли это, что это исправление является лишь обходным решением для ошибки в компиляторе? – Dylan

+0

А теперь я вижу, что 'S' не суперкласс - это просто взгляд (в некотором смысле). Таким образом, оценка взглядов является более подходящей, несмотря на то, что в большинстве случаев она не требуется. – Dylan

 Смежные вопросы

  • Нет связанных вопросов^_^