Один класс на файл
Кому какое дело? Я предпочитаю целые программы, содержащиеся в одном файле, а не миллион разных файлов.
Он используется в интерпретаторах последовательностей (например, в Python для понимания списков и генераторов, где вы также можете использовать yield
).
Это так. применяется в сочетании с для
и записывает новый элемент в результирующую последовательность.
Простой пример (из 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 yield
имеет другой эффект.
Да, как сказал Эрвикер, он в значительной степени эквивалентен LINQ select
и имеет очень мало общего с Ruby и Python yield
. По сути, там, где в C # вы бы написали
from ... select ???
, в Scala у вас есть
for ... yield ???
. Также важно понимать, что для
-пониманий работают не только с последовательностями, но и с любым типом, который определяет определенные методы. , как и LINQ:
карту
, он разрешает для
-выражений, состоящих из
одиночный генератор. flatMap
, а также карту
, он позволяет для
-выражений, состоящих
из нескольких генераторов. foreach
, он разрешает для
-циклов без выхода (как с одним, так и с несколькими генераторами).
, он позволяет для выражений
-фильтра, начинающихся с if
в выражении для
. Вот мое понимание, если вы не получите более точный ответ от пользователя Scala (а я - нет).
Он появляется только как часть выражения, начинающегося с для
, в котором говорится, как сгенерировать новый список из существующего.
Что-то вроде:
var doubled = for (n <- original) yield n * 2
Итак, есть один выходной элемент для каждого входа (хотя я считаю, что есть способ отбросить дубликаты).
Это сильно отличается от «императивного продолжения», обеспечиваемого yield на других языках, где он предоставляет способ генерировать список любой длины из некоторого императивного кода практически с любой структурой.
(Если вы знакомы с C #, это ближе к оператору LINQ select
, чем к yield return
).
Я думаю, что принятый ответ хорош, но похоже, что многие люди не смогли понять некоторые фундаментальные моменты.
Во-первых, Scala для
понимания эквивалентна нотации Haskell do
, и это не более чем синтаксический сахар для композиции нескольких монадических операций. Поскольку это утверждение, скорее всего, не поможет никому, кому нужна помощь, давайте попробуем еще раз…: -)
Scala для
понимания - это синтаксический сахар для композиции нескольких операций с картой, flatMap
и фильтр
. Или foreach
. Scala фактически переводит выражение для
в вызовы этих методов, поэтому любой класс, предоставляющий их, или их подмножество, можно использовать для понимания.
Во-первых, давайте поговорим о переводах. Есть очень простые правила:
Это
для (x <- c1; y <- c2; z <-c3) {...}
переводится в
c1.foreach (x => c2.foreach (y => c3.foreach (z => {...})))
Это
для (x <- c1; y <- c2; z <- c3) yield {...}
переведено в
c1.flatMap (x => c2.flatMap (y => c3.map (z => {...})))
Это
для (x <- c; if cond) yield {...}
переведен на Scala 2.7 в
c.filter (x => cond) .map (x => {...})
или, в Scala 2.8, в
c.withFilter (x => cond) .map (x => {...})
с возвратом к первому, если метод withFilter
недоступен, а фильтр
есть. Дополнительную информацию об этом см. В разделе ниже.
This
for (x <- c; y = ...) yield {...}
переводится в
c.map (x => (x, ...)). Map ((x, y) => {...})
Если посмотреть на очень простые для
понимания, альтернативы map
/ 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
withFilter
В Scala 2.8 появился метод под названием withFilter
, основное отличие которого состоит в том, что вместо возврата новой отфильтрованной коллекции , он фильтрует по запросу. Поведение метода фильтра
определяется на основе строгости коллекции. Чтобы лучше понять это, давайте взглянем на Scala 2. 7 со списком
(строгий) и поток
(нестрогий):
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
Разница возникает из-за того, что фильтр
сразу применяется к списку
], возвращая список вероятностей - поскольку найдено,
является ложным
. Только тогда выполняется foreach
, но к этому времени изменение найдено
бессмысленно, поскольку фильтр
уже выполнен.
В случае ] Stream
, условие не применяется сразу. Вместо этого, поскольку каждый элемент запрашивается foreach
, фильтр
проверяет условие, которое позволяет foreach
влиять на него через найдено
. Чтобы прояснить, вот эквивалентный код для понимания:
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
Это дает результат, ожидаемый большинством людей, без изменения поведения фильтра
. В качестве примечания: Диапазон
был изменен с нестрогого на строгий между Scala 2.7 и Scala 2.8.
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
Это дает результат, ожидаемый большинством людей, без изменения поведения фильтра
. В качестве примечания: Диапазон
был изменен с нестрогого на строгий между Scala 2.7 и Scala 2.8.
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
Это дает результат, ожидаемый большинством людей, без изменения поведения фильтра
. В качестве примечания: Диапазон
был изменен с нестрогого на строгий между Scala 2.7 и Scala 2.8.