Почему Scala возвращается, но не ломается и продолжает

22

Scala не имеет breakили continue, поэтому некоторое циклическое поведение требует немного больше размышлений.

Раннее завершение цикла требует хвостовой рекурсии, исключений или scala.util.control.Breaks(которые используют исключения).

Основанием для этого является то, что gotoони , как и они, представляют собой потоковые конструкции, которые затеняют поток и могут быть выполнены лучшими, менее удивительными способами.

Но, похоже, те же аргументы могут быть использованы для return.

Почему Скала намеренно опускается breakи continue, но не return?

Пол Дрейпер
источник
1
Я могу себе представить , что авторы языка считают хвостовую рекурсию , как на пути построения итерации. Я могу себе это представить, breakи мне continueпонадобится дополнительная уборочная техника. OTOH return- это способ упорядоченного завершения функции, и любое оборудование для очистки уже существует.
9000
1
Есть breakable { for { break; } }только запоздалая мысль, и, вероятно, далеко не эффективная.
Joop Eggen
Потому что с функциями на самом деле нет причин для этого. То же самое в питоне. Каждый раз, когда вы используете цикл for с break, вы можете вместо этого написать функцию, поместить свой цикл в функцию и использовать return. Я не могу вспомнить ситуацию, когда это не очень хорошая идея в отношении чистого кода. Что касается производительности, очистка может быть лучше, но производительность не имеет наивысшего приоритета в scala.
Валентри
2
На этот вопрос, похоже, здесь есть ответ: stackoverflow.com/questions/3770989/…
Майкл Шоу,
3
@PaulDraper: ответ для breakи continueсодержится в вашем вопросе и в ссылке в вашем вопросе. Вопрос в returnтом, о чём именно был связан вопрос, на который я ссылался, и на который был дан ответ, по крайней мере, в ответе, получившем наибольшее количество голосов. Если два ответа вместе не отвечают на ваш вопрос, возможно, вы могли бы отредактировать вопрос, чтобы уточнить его.
Майкл Шоу

Ответы:

16

Перерыв и продолжить:

В своем выступлении о Scala Мартин Одерский назвал 3 причины не включать перерыв или продолжить работу на слайде 22:

  • Они немного необходимы; лучше использовать много мелких функций.
  • Вопросы, как взаимодействовать с замыканиями.
  • Они не нужны!

И тогда он говорит: «Мы можем поддерживать их исключительно в библиотеках». На слайде 23 он дает код, который реализует break. Хотя я не достаточно хорошо знаю Scala, чтобы быть уверенным, похоже, что короткий фрагмент на этом слайде - это все, что нужно для реализации break, и это continueможет быть реализовано в коде, который также короток.

Возможность реализовывать подобные вещи в библиотеках упрощает основной язык.

В «Программировании в Scala, второе издание» Мартина Одерского, Лекса Спуна и Билла Веннерса дается следующее объяснение:

Возможно, вы заметили, что там не было упоминания breakили continue. Scala пропускает эти команды, потому что они плохо сочетаются с функциональными литералами ... Понятно, что continueозначает внутри whileцикла, но что это будет означать внутри литерала функции? ... Существует множество способов программирования без breakи continue, и, если вы используете функциональные литералы, эти альтернативы часто могут быть короче исходного кода.

Возвращение:

Возвраты могут считаться немного обязательными по стилю, поскольку return - это глагол, команда, которая что-то делает. Но их также можно увидеть в чисто функциональном / декларативном виде: они определяют, что является возвращаемым значением функции (даже если в функции с множественными возвращениями они дают только частичное определение).

В той же книге говорится о следующем return:

При отсутствии какого-либо явного returnутверждения метод Scala возвращает последнее значение, вычисленное методом. Рекомендуемый стиль для методов на самом деле состоит в том, чтобы избегать явных и особенно множественных returnоператоров. Вместо этого думайте о каждом методе как о выражении, которое возвращает одно значение, которое возвращается.

Методы завершают работу и возвращают значение, даже если returnоператор не используется, поэтому с замыканиями проблем быть не может, так как в противном случае замыкания не сработают.

Также не может быть проблем с зацеплением с функциональными литералами, так как функция все равно должна возвращать значение.

Майкл Шоу
источник
2
Что касается возвращения, то здесь, похоже, есть некоторые умеренные опасности: tpolecat.github.io/2014/05/09/return.html
bbarker
0

Я думаю, что предыдущие ответы отдают должное проблемам определения семантики для breakили continueв языковой форме для Scala с относительно непринужденным контекстом.

Я написал небольшую библиотеку, которая определяет breakи continueв более ограниченном контексте: итерации по последовательностям через Scala для-понимания. Сосредоточив внимание на этом контексте, я считаю, что семантика становится однозначной и легко обоснованной.

Библиотека доступна здесь: https://github.com/erikerlandson/breakable

Вот простой пример того, как это выглядит в коде:

scala> import com.manyangled.breakable._
import com.manyangled.breakable._

scala> val bkb2 = for {
     |   (x, xLab) <- Stream.from(0).breakable   // create breakable sequence with a method
     |   (y, yLab) <- breakable(Stream.from(0))  // create with a function
     |   if (x % 2 == 1) continue(xLab)          // continue to next in outer "x" loop
     |   if (y % 2 == 0) continue(yLab)          // continue to next in inner "y" loop
     |   if (x > 10) break(xLab)                 // break the outer "x" loop
     |   if (y > x) break(yLab)                  // break the inner "y" loop
     | } yield (x, y)
bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = com.manyangled.breakable.Breakable@34dc53d2

scala> bkb2.toVector
res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))
эже
источник