Я понимаю доходность Ruby и Python. Что делает урожай Scala?
312
Я понимаю доходность Ruby и Python. Что делает урожай Scala?
Он используется в понимании последовательностей (например, в списках и генераторах Python, где вы yield
тоже можете использовать ).
Он применяется в сочетании с for
и записывает новый элемент в результирующую последовательность.
Простой пример (из Скала-Ланга )
/** Turn command line arguments to uppercase */
object Main {
def main(args: Array[String]) {
val res = for (a <- args) yield a.toUpperCase
println("Arguments: " + res.toString)
}
}
Соответствующее выражение в F # будет
[ for a in args -> a.toUpperCase ]
или
from a in args select a.toUpperCase
в Линк.
Ruby's yield
имеет другой эффект.
Я думаю, что принятый ответ великолепен, но, похоже, многим не удалось понять некоторые фундаментальные моменты.
Во-первых,
for
понимание Scala эквивалентноdo
нотации Хаскелла , и это не более чем синтаксический сахар для составления множества монадических операций. Поскольку это утверждение, скорее всего, не поможет никому, кто нуждается в помощи, давайте попробуем еще раз… :-)Понимание Scala
for
является синтаксическим сахаром для составления множества операций с картой,flatMap
иfilter
. Илиforeach
. Scala фактически переводитfor
-выражение в вызовы этих методов, поэтому любой класс, предоставляющий их, или их подмножество, можно использовать для понимания.Сначала поговорим о переводах. Есть очень простые правила:
это
переводится на
это
переводится на
это
переведено на Scala 2.7 в
или на Scala 2.8, в
с запасным вариантом, если метод
withFilter
недоступен, ноfilter
есть. Пожалуйста, смотрите раздел ниже для получения дополнительной информации по этому вопросу.это
переводится на
Когда вы смотрите на очень простые
for
постижениях, чтоmap
/foreach
альтернативы выглядят, действительно, лучше. Однако, как только вы начнете их составлять, вы можете легко потеряться в скобках и уровнях вложенности. Когда это происходит,for
понимание обычно намного яснее.Я покажу один простой пример и намеренно опущу любое объяснение. Вы можете решить, какой синтаксис было легче понять.
или
withFilter
В Scala 2.8 появился метод с именем
withFilter
, основное отличие которого заключается в том, что вместо возврата новой отфильтрованной коллекции он фильтрует по требованию.filter
Метод имеет свое поведение , определенное на основе строгости коллекции. Чтобы лучше это понять, давайте взглянем на Scala 2.7 сList
(строгим) иStream
(не строгим):Разница возникает потому, что
filter
сразу применяется сList
, возвращая список шансов - так какfound
естьfalse
. Только тогдаforeach
выполняется, но к этому времени изменение неfound
имеет смысла, какfilter
уже выполнено.В случае
Stream
, условие не применяется немедленно. Вместо этого, поскольку каждый элемент запрашиваетсяforeach
,filter
проверяется условие, которое позволяетforeach
на него влиятьfound
. Просто чтобы прояснить, вот эквивалентный код для понимания:Это вызвало много проблем, потому что люди ожидали, что они
if
будут рассматриваться по требованию, а не применяться ко всей коллекции заранее.Представлена Scala 2.8
withFilter
, которая всегда не является строгой, независимо от строгости коллекции. Следующий пример показываетList
оба метода в Scala 2.8:Это дает результат, которого ожидает большинство людей, без изменения
filter
поведения. В качестве примечания,Range
между Scala 2.7 и Scala 2.8 был изменен с нестрогого на строгий.источник
withFilter
Предполагается, что он также не является строгим, даже для строгих коллекций, что заслуживает некоторого объяснения Я рассмотрю это ...for(x <- c; y <- x; z <-y) {...}
переведено наc.foreach(x => x.foreach(y => y.foreach(z => {...})))
2.for(x <- c; y <- x; z <- y) yield {...}
переведено наc.flatMap(x => x.flatMap(y => y.map(z => {...})))
for(x <- c; y = ...) yield {...}
действительно переведено наc.map(x => (x, ...)).map((x,y) => {...})
? Я думаю, что это переведеноc.map(x => (x, ...)).map(x => { ...use x._1 and x._2 here...})
или я что-то упустил?Да, как сказал Уорвикер, он в значительной степени эквивалентен LINQ
select
и имеет мало общего с Ruby и Pythonyield
. В основном, где в C # вы бы написалив Scala у вас есть вместо
Также важно понимать, что
for
-comprehensions работают не только с последовательностями, но и с любым типом, который определяет определенные методы, например LINQ:map
, он разрешаетfor
выражения, состоящие из одного генератора.flatMap
так же, какmap
, он допускаетfor
выражения, состоящие из нескольких генераторов.foreach
, он допускаетfor
-loops без выхода (как с одним, так и с несколькими генераторами).filter
, он разрешаетfor
выражения -filter, начинающиеся с выраженияif
вfor
выражении.источник
Если вы не получите лучший ответ от пользователя Scala (которым я не являюсь), вот мое понимание.
Он появляется только как часть выражения, начинающегося с
for
, в котором указано, как создать новый список из существующего списка.Что-то вроде:
Таким образом, есть один элемент вывода для каждого ввода (хотя я считаю, что есть способ отбрасывания дубликатов).
Это сильно отличается от «императивных продолжений», доступных в yield в других языках, где он позволяет генерировать список любой длины из некоторого императивного кода практически с любой структурой.
(Если вы знакомы с C #, он ближе к оператору LINQ,
select
чем к немуyield return
).источник
Ключевым словом
yield
в Scala является просто синтаксический сахар, который можно легко заменить на amap
, как подробно объяснял Даниэль Собрал .С другой стороны,
yield
абсолютно вводит в заблуждение, если вы ищете генераторы (или продолжения), подобные тем, что есть в Python . Посмотрите эту ветку SO для получения дополнительной информации: Каков предпочтительный способ реализации yield в Scala?источник
Рассмотрим следующее для понимания
Может быть полезно прочитать это вслух следующим образом
« Для каждого целого числа
i
, если оно больше, чем3
, тогда выведите (произведите)i
и добавьте его в списокA
».С точки зрения математической нотации построителя множеств вышеупомянутое для понимания аналогично
который может быть прочитан как
« Для каждого целого числа , если оно больше, чем оно , оно является членом множества ».
или в качестве альтернативы
« это набор всех целых чисел , так что каждое из них больше, чем .»
источник
Выход аналогичен циклу for, в котором есть буфер, который мы не видим, и для каждого приращения он продолжает добавлять следующий элемент в буфер. Когда цикл for завершает работу, он возвращает коллекцию всех полученных значений. Выход можно использовать как простые арифметические операторы или даже в сочетании с массивами. Вот два простых примера для вашего лучшего понимания
res: scala.collection.immutable.IndexedSeq [Int] = Vector (3, 6, 9, 12, 15)
res: Seq [(Int, Char)] = Список ((1, a), (1, b), (1, c), (2, a), (2, b), (2, c), ( 3, а), (3, б), (3, в))
Надеюсь это поможет!!
источник
Эти две части кода эквивалентны.
Эти две части кода также эквивалентны.
Карта так же гибка, как доходность и наоборот.
источник
yield является более гибким, чем map (), см. пример ниже
yield выдаст результат наподобие: List (5, 6), что хорошо
в то время как map () вернет результат в виде: List (false, false, true, true, true), что, вероятно, не то, что вы намереваетесь.
источник