Чому Scala вимагає, щоб функції мали явний тип повернення?


11

Нещодавно я почав вчитися програмувати в Scala, і до цього часу було весело. Мені дуже подобається здатність оголошувати функції в межах іншої функції, яка просто здається інтуїтивно зрозумілою.

Одним із поглядів домашніх улюбленців, що у мене є щодо Scala, є те, що Scala вимагає явного типу повернення у своїх функціях . І я відчуваю, що це заважає виразності мови. Крім того, просто важко запрограмувати цю вимогу. Можливо, це тому, що я родом з Javascript та Ruby zone комфорту. Але для такої мови, як Скала, яка матиме багато пов'язаних функцій у додатку, я не можу уявити, як саме в моєму голові буває мозковий штурм, який тип функції, про яку я пишу, повинен повертатися з рекурсіями після рекурсій.

Ця вимога явного декларування типу повернення щодо функцій, не турбуйте мене для таких мов, як Java та C ++. Рекурсії на Java та C ++, коли вони траплялися, часто розбиралися з 2 до 3 функціями макс. Ніколи кілька функцій, пов'язаних між собою, як Scala.

Тож, напевно, мені цікаво, чи є вагома причина, чому у Scala повинна бути вимога функцій, що мають явний тип повернення?


5
Це не так - і я не розумію, чому це було б проблемою, якби це було.
Кіт Томпсон

1
Я думав, що це так. Чи є в Scala випадки, коли тип повернення для функції насправді неоднозначний?
вивезення сміття

Відповіді:


15

Scala не вимагає явного типу повернення для всіх функцій, лише рекурсивних. Причиною тому є те, що алгоритм виводу типу Scala - це щось, що є близьким до простого сканування від початку до кінця, яке не може виконувати пошук.

Це означає, що така функція:

def fortuneCookieJoke(message: String) = message + " in bed."

не потрібен тип повернення, оскільки компілятор Scala може чітко бачити, не використовуючи логічні змінні чи дивлячись ні на що, крім параметрів методу, що тип повернення повинен бути String.

З іншого боку, така функція:

def mapInts(f: (Int) => Int, l: List[Int]) = l match {
  case Nil => Nil
  case x :: xs => f(x) :: mapInts(f, xs)
}

призведе до помилки часу компіляції, оскільки компілятор Scala не може бачити, не використовуючи ні перегляду lookahead, ні логічні змінні, що саме є тип mapInts. Найбільше, що можна сказати, якби воно було досить розумним, - це те, що тип повернення є супертипом List[Nothing], оскільки Nilє цього типу. Це не дає ніде поблизу достатньо інформації, щоб точно визначити тип повернення mapInts.

Зверніть увагу, що це характерно для Scala, і що існують й інші статично типізовані мови (більшість сімейства Міранда / Хаскелл / Чистий, більша частина сімейства ML та кілька розпорошених інших), які використовують набагато більш вичерпні та спроможні алгоритми виводу типу ніж використовує Scala. Також майте на увазі, що це не зовсім вина Scala; номінальне підтипування та виведення цілого модуля принципово не суперечать один одному, і дизайнери Scala вирішили віддати перевагу першому над останнім заради сумісності з Java, тоді як "чистіші" статично типовані функціональні мови були здебільшого розроблені з протилежний вибір на увазі.


4
Власне, проблема полягає не в тому, щоб розробити більш всебічний алгоритм посилення типу. Це розробка більш всеохоплюючого алгоритму поширення типу, зберігаючи високу якість повідомлень про помилки в поточному компіляторі Scala.
Йорг W Міттаг

1
Чи не було б правильним повернення case Nilсправді порожнім List[Int]()? У цьому випадку достатньо розумний компілятор міг би це зрозуміти. Хоча, це все грає адвоката диявола.
KChaloux
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.