Почему scala не может определить тип в частичном методе? - PullRequest
9 голосов
/ 19 августа 2011

См. Этот пример:

def hello(a:String, b:String) = println(a + ":" + b)
val m1 = hello("aaa", _ )
m1("bbb")

Он не может быть скомпилирован, мне нужно добавить тип к частичному методу:

val m1 = hello("aaa", _: String)

Почему scala не знает, что второй параметр метода hello равен String?

Ответы [ 3 ]

15 голосов
/ 19 августа 2011

Вывод типа Scala основан на потоке.Методы и функции нуждаются в явных типах параметров, которые используются для вывода других типов.Типы параметров не могут быть выведены из метода или тела функции.Иногда, однако, типы параметров известны из внешнего контекста, и их не нужно маркировать.Два примера:

val f: String => Unit = hello("aaa", _)
val s = Seq(1,2).map(_+1) // Seq[Int].map expects a function of Int argument type

Ниже приведена цитата Мартина Одерского об ограничениях вывода типов в Scala по сравнению, скажем, с ML и Haskell.Сложности включают в себя перегрузку Scala, выбор записей и подтипирование, а также необходимость упростить задачу:

Причина, по которой у Scala нет вывода типа Хиндли / Милнера, заключается в том, что его очень трудно комбинировать стакие функции, как перегрузка (специальный вариант, не классы типов), выбор записей и подтипирование.Я не говорю невозможное - существует ряд расширений, которые включают эти функции;На самом деле, я сам был в отношении некоторых из них.Я просто говорю, что очень трудно заставить это работать хорошо на практике, где нужно иметь небольшие шрифтовые выражения и хорошие сообщения об ошибках.Это также не закрытый случай - многие исследователи работают над расширением границ (посмотрите, например, на MLF Реми).Но сейчас это компромисс между лучшим выводом типа и лучшей поддержкой этих функций.Вы можете сделать компромисс в обоих направлениях.Тот факт, что мы хотели интегрироваться с Java, склонял чашу весов в пользу подтипов и отдаленных от Хиндли / Милнера.

Источник: комментарий под постом Вывод универсального типа - плохая вещь.

4 голосов
/ 20 августа 2011

Проще говоря, Scala использует типы параметров для поиска подходящего метода, а не тип метода для определения типа параметров.

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

3 голосов
/ 19 августа 2011

Возможно, это связано с возможной двусмысленностью этого определения, так как hello может быть перегружен.

// inside some class context
def hello(a:String, b:String) = println(a + ":" + b)
def hello(a:String, b:Int) = println(a + ":" + b.toString)
val m1 = hello("aaa", _ ) // which one to choose?

Учтите, что не только вы можете сделать val m1 = hello("aaa", _). Там может быть пользователь вашего класса, делающий val my_hello = (new C).hello("aaa", _). А затем вы нарушаете совместимость исходного кода, добавляя перегрузку к исходному методу приветствия строки, потому что вдруг уже не понятно, что делать.

Я не уверен, что это единственная причина, но, безусловно, это можно рассматривать как меру безопасности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...