Каков урожай Scala?

Один класс на файл

Кому какое дело? Я предпочитаю целые программы, содержащиеся в одном файле, а не миллион разных файлов.

308
задан Peter Mortensen 6 May 2013 в 06:28
поделиться

4 ответа

Он используется в интерпретаторах последовательностей (например, в 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 имеет другой эффект.

204
ответ дан 23 November 2019 в 01:14
поделиться

Да, как сказал Эрвикер, он в значительной степени эквивалентен LINQ select и имеет очень мало общего с Ruby и Python yield . По сути, там, где в C # вы бы написали

from ... select ??? 

, в Scala у вас есть

for ... yield ???

. Также важно понимать, что для -пониманий работают не только с последовательностями, но и с любым типом, который определяет определенные методы. , как и LINQ:

  • Если ваш тип определяет только карту , он разрешает для -выражений, состоящих из одиночный генератор.
  • Если он определяет flatMap , а также карту , он позволяет для -выражений, состоящих из нескольких генераторов.
  • Если он определяет foreach , он разрешает для -циклов без выхода (как с одним, так и с несколькими генераторами).
  • Если он определяет фильтр , он позволяет для выражений -фильтра, начинающихся с if в выражении для .
23
ответ дан 23 November 2019 в 01:14
поделиться

Вот мое понимание, если вы не получите более точный ответ от пользователя Scala (а я - нет).

Он появляется только как часть выражения, начинающегося с для , в котором говорится, как сгенерировать новый список из существующего.

Что-то вроде:

var doubled = for (n <- original) yield n * 2

Итак, есть один выходной элемент для каждого входа (хотя я считаю, что есть способ отбросить дубликаты).

Это сильно отличается от «императивного продолжения», обеспечиваемого yield на других языках, где он предоставляет способ генерировать список любой длины из некоторого императивного кода практически с любой структурой.

(Если вы знакомы с C #, это ближе к оператору LINQ select , чем к yield return ).

13
ответ дан 23 November 2019 в 01:14
поделиться

Я думаю, что принятый ответ хорош, но похоже, что многие люди не смогли понять некоторые фундаментальные моменты.

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

Scala для понимания - это синтаксический сахар для композиции нескольких операций с картой, flatMap и фильтр . Или foreach . Scala фактически переводит выражение для в вызовы этих методов, поэтому любой класс, предоставляющий их, или их подмножество, можно использовать для понимания.

Во-первых, давайте поговорим о переводах. Есть очень простые правила:

  1. Это

     для (x <- c1; y <- c2; z <-c3) {...}
    

    переводится в

     c1.foreach (x => c2.foreach (y => c3.foreach (z => {...})))
    
  2. Это

     для (x <- c1; y <- c2; z <- c3) yield {...}
    

    переведено в

     c1.flatMap (x => c2.flatMap (y => c3.map (z => {...})))
    
  3. Это

     для (x <- c; if cond) yield {...}
    

    переведен на Scala 2.7 в

     c.filter (x => cond) .map (x => {...})
    

    или, в Scala 2.8, в

     c.withFilter (x => cond) .map (x => {...})
    

    с возвратом к первому, если метод withFilter недоступен, а фильтр есть. Дополнительную информацию об этом см. В разделе ниже.

  4. 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.

811
ответ дан 23 November 2019 в 01:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: