Я понимаю доходность Ruby и Python. Что делает урожай Скалы?Что такое выход Scala?
ответ
Используется в sequence comprehensions (например, для составления списков и генераторов Python, где вы также можете использовать yield
).
Он применяется в сочетании с for
и записывает новый элемент в результирующую последовательность.
Простой пример (из scala-lang)
/** 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
в Linq.
Ruby's yield
имеет значение.
Если вы не получите лучшего ответа от пользователя Scala (которого я не знаю), вот мое понимание.
Он появляется только как часть выражения, начинающегося с for
, в котором говорится, как сгенерировать новый список из существующего списка.
Что-то вроде:
var doubled = for (n <- original) yield n * 2
Таким образом, есть один выходной элемент для каждого входа (хотя я считаю, что есть способ отбрасывания дубликатов).
Это сильно отличается от «императивных продолжений», разрешенных выходом на других языках, где он предоставляет способ генерации списка любой длины из некоторого императивного кода с почти любой структурой.
(Если вы знакомы с C#, это ближе к LINQ'sselect
операторам, чем к yield return
).
это должно быть «var doubled = for (n <- original) yield n * 2 ". –
Это тот, который я могу легко и ясно понять. –
Да, как сказал Эрвиккер, это в значительной степени эквивалентно LINQ и имеет очень мало общего с Ruby's и Python's yield
. В принципе, где в C# можно было бы написать
from ... select ???
в Scala у вас есть вместо
for ... yield ???
Это также важно понимать, что for
-comprehensions не просто работать с последовательностями, но и с любым типом, который определяет определенные методы, так же, как LINQ:
- Если ваш тип определяет только
map
, это позволяетfor
-expressions, состоящий из одиночный генератор. - Если он определяет
flatMap
, а такжеmap
, он позволяет получитьfor
-выражения, состоящие из нескольких генераторов. - Если он определяет
foreach
, он позволяетfor
-loops без выхода (как с одним, так и с несколькими генераторами). - Если он определяет
filter
, он позволяет выражатьfor
-фильтров, начиная сif
в выраженииfor
.
в LINQ C#, правильный порядок -« из ... select ??? » –
@ Eldritch Conundrum - Что интересно, это тот же порядок, в котором исходные спецификации спецификаций SQL. Где-то по пути язык SQL перевернул порядок, но имеет смысл сначала описать то, что вы вытаскиваете, за которым следует то, что вы ожидаете от него. –
Я думаю, что принятый ответ велик, но, похоже, многие люди не смогли понять некоторые фундаментальные моменты.
Во-первых, «понимание» Scala эквивалентно нотации Haskell «do», и это не что иное, как синтаксический сахар для композиции нескольких монадических операций. Поскольку это заявление, скорее всего, не поможет никому, кто нуждается в помощи, давайте попробуем еще раз ... :-)
«Сказочные» решения Scala - это синтаксический сахар для составления нескольких операций с картой, плоской матрицей и фильтром. Или проследить. Scala фактически переводит выражение for в вызовы этих методов, поэтому любой класс, предоставляющий их, или их подмножество, может использоваться для понимания.
Прежде всего, давайте поговорим о переводах. Есть очень простые правила:
1) Это
for(x <- c1; y <- c2; z <-c3) {...}
переводится в
c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))
2) Этот
for(x <- c1; y <- c2; z <- c3) yield {...}
переводится в
c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
3) Эта
for(x <- c; if cond) yield {...}
переводится на Scala 2.7 в
c.filter(x => cond).map(x => {...})
или, Scala 2.8, в
c.withFilter(x => cond).map(x => {...})
с запасным вариантом в прежнем, если метод withFilter
является не доступно, но filter
есть. Подробнее см. Ниже.
4) Это
for(x <- c; y = ...) yield {...}
переводится в
c.map(x => (x, ...)).map((x,y) => {...})
Когда вы смотрите на очень простой для постижений, альтернативы карта/Foreach выглядят, действительно, лучше. Однако, если вы начнете их составлять, вы можете легко потеряться в скобках и уровнях вложенности. Когда это случается, для понимания, как правило, гораздо яснее.
Я покажу один простой пример и намеренно опускаю любые объяснения. Вы можете решить, какой синтаксис легче понять.
l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length))
или
for{
sl <- l
el <- sl
if el > 0
} yield el.toString.length
РЕДАКТИРОВАТЬ
Скала 2.8 введен метод, называемый withFilter
, основная разница в том, что, вместо возврата нового, фильтруют, сбор, он фильтрует на- спрос. Метод filter
имеет свое поведение, основанное на строгости коллекции. Чтобы лучше это понять, давайте посмотрим на некоторые Scala 2.7 с List
(строгой) и Stream
(нестрогого):
scala> var found = false
found: Boolean = false
scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9
scala> found = false
found: Boolean = false
scala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
Разница происходит потому, что фильтр будет немедленно применен с List
, возвращая список шансов - - с found
- false
. Только тогда выполняется foreach
, но к этому времени изменение found
бессмысленно, так как filter
уже выполнено.
В случае Stream
это условие не применяется немедленно. Вместо этого, поскольку каждый элемент запрашивается foreach
, filter
проверяет состояние, которое позволяет foreach
влиять на него через found
. Просто чтобы понять, вот код эквивалента постижения:
for (x <- List.range(1, 10); if x % 2 == 1 && !found)
if (x == 5) found = true else println(x)
for (x <- Stream.range(1, 10); if x % 2 == 1 && !found)
if (x == 5) found = true else println(x)
Это вызвало много проблем, потому что люди ожидали if
рассматривать по требованию, вместо того, применяется ко всей коллекции заранее.
Scala 2.8 представил withFilter
, который является всегда нестрогим, независимо от его строгости. Следующий пример показывает List
с обоими методами на Scala 2.8:
scala> var found = false
found: Boolean = false
scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9
scala> found = false
found: Boolean = false
scala> List.range(1,10).withFilter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
Это дает результат большинство людей ожидают, без изменения, как filter
ведет себя. В качестве побочного примечания, Range
был изменен с нестрого на строго между Scala 2.7 и Scala 2.8.
Существует новый метод withFilter в scala 2.8. for (x <- c; if cond) yield {...} перевести на c.withFilter (x => cond) .map (x => {...}) в scala2.8. – Eastsun
@ Eastsun Правда, хотя есть и автоматический откат. 'withFilter' также должен быть нестрогим, даже для строгих коллекций, который заслуживает некоторого объяснения. Я рассмотрю это ... –
Один из лучших ответов, которые я видел на SO. +1 – Allyn
Ключевое слово yield
в Scala просто синтаксический сахар, который может быть легко заменен map
как Daniel Sobral already explained подробно.
С другой стороны, yield
абсолютно вводит в заблуждении, если вы ищете генераторы (или продолжения), подобные those in Python. Смотрите эту SO нить для получения дополнительной информации: What is the preferred way to implement 'yield' in Scala?
Хорошая точка ...! –
выхода является более гибким, чем карты(), смотрите пример ниже
val aList = List(1,2,3,4,5)
val res3 = for (al <- aList if al > 3) yield al + 1
val res4 = aList.map(_+ 1 > 3)
println(res3)
println(res4)
выхода напечатают результат как: Список (5, 6), что хорошо
, в то время как map() вернет результат, например: List (false, false, true, true, true), что, вероятно, не то, что вы намереваетесь.
Это сравнение неверно. Вы сравниваете две разные вещи. Выражение в доходности никоим образом не делает то же самое, что выражение на карте. Кроме того, он не показывает «гибкость» урожая по сравнению с картой вообще. – dotnetN00b
выход al + 1> 3 сделал бы тот же трюк – philix
val aList = List(1,2,3,4,5)
val res3 = for (al <- aList if al > 3) yield al + 1
val res4 = aList.filter(_ > 3).map(_ + 1)
println(res3)
println(res4)
Эти две части кода являются эквивалентными.
val res3 = for (al <- aList) yield al + 1 > 3
val res4 = aList.map(_+ 1 > 3)
println(res3)
println(res4)
Эти два фрагмента кода также эквивалентны.
Карта такая же гибкая, как и урожайность, и наоборот.
Рассмотрим следующий for-comprehension
val A = for (i <- Int.MinValue to Int.MaxValue; if i > 3) yield i
Это может быть полезно прочитать его вслух следующим
"Для каждого целого i
, если это больше, чем 3
, то выход (произвести) i
и добавить его в список A
. "
С точки зрения математической set-builder notation, выше для-понимания аналогично
, которые могут быть прочитаны, как
"Для каждое целое число , , если это превышает , тогда это является членом из набора . "
или в качестве альтернативы, как
« есть множество всех целых чисел , таким образом, что каждая больше, чем .»
- 1. Что такое выход? Как?
- 2. Scala: что такое CompactBuffer?
- 3. Что такое уточнение Scala?
- 4. Что такое '_ =' в scala?
- 5. Что такое выход? C Программирование
- 6. Что такое «выход» в PowerShell?
- 7. Что такое: + линия в scala?
- 8. slick & scala: Что такое TableQueries?
- 9. Что такое "Scala Presentation Compiler"?
- 10. Что такое [A] в Scala?
- 11. Что такое A * в Scala?
- 12. Что такое «0» в Scala?
- 13. Что такое "!" означает в scala?
- 14. Что такое ClassManifest в Scala?
- 15. Что такое РНК в scala?
- 16. Что такое стандартные исключения Scala?
- 17. Что такое выход System.getProperty ("user.home") в windows?
- 18. Что такое «Сбежавшие» и «неэкранированные» выход
- 19. Что такое выход во время сборки PyPy?
- 20. Что такое символ подчеркивания, используемый в Scala?
- 21. Что такое ключевое слово forSome в Scala?
- 22. Что такое эквивалент Scala статического блока Java?
- 23. Scala: Что такое ключевое слово opt?
- 24. Что такое приложение для убийцы Scala?
- 25. Что такое хэш-функция Scala для строк?
- 26. Что такое | символ >> в Scala
- 27. Что такое эквивалент Clojure для seq.reduceOption Scala?
- 28. Что такое временная сложность среза в scala?
- 29. Что такое эквивалент Clojure для zipWithIndex Scala?
- 30. Что такое стандартные монады Scala, кроме опциона?
Итак, почему я должен использовать доход вместо карты? Этот код карты эквивалентен val res = args.map (_. ToUpperCase), правильно? – Geo
Если вам нравится синтаксис лучше. Кроме того, как отмечает alexey, понимание также обеспечивает хороший синтаксис для доступа к flatMap, filter и foreach. –
Я бы предпочел синтаксис карты args {_ toUpperCase} лично, поскольку он «чувствует» намного больше OO. Похоже, что в соответствии с целью Scala, предоставляемой через библиотечную поддержку, доступно только на других языках через специальные конструкции и ключевые слова. –