Какова доходность Scala?



Я понимаю выход Рубина и питона. Что делает выход Scala?

631   9  

9 ответов:

он используется в осмысление последовательности (как список 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.

Рубин yield имеет другой эффект.

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

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

Скала for понимание является синтаксическим сахаром для композиции несколько операций с картой, flatMap и filter. Или foreach. Scala фактически переводит a 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 => {...})
    

    с резервным вариантом в первый метод if withFilter но filter есть. Дополнительную информацию см. В разделе ниже этот.

  4. этой

    for(x <- c; y = ...) yield {...}
    

    переведена на

    c.map(x => (x, ...)).map((x,y) => {...})
    

когда вы смотрите на очень простой for генераторы, в map/foreach альтернативы выглядят, действительно, лучше. Однако, как только вы начнете их составлять, вы можете легко потеряться в скобках и уровнях вложенности. Когда это произойдет, for генераторы, как правило, гораздо яснее.

я покажу один простой пример, и намеренно опустить никакое объяснение. Вы можете решить, какой синтаксис был легче понять.

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, основное отличие которого заключается в том, что вместо возврата новой, отфильтрованной коллекции он фильтрует по требованию. Элемент 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

разница происходит потому, что filter немедленно применяется с 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.

да, как сказал Ушастик, это в значительной степени эквивалентно LINQ's select и имеет очень мало общего с Руби и Пайтона yield. В принципе, где в C# вы должны написать

from ... select ??? 

в Scala у вас вместо

for ... yield ???

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

  • если ваш тип определяет только map, это позволяет for-выражения, состоящие из один генератор.
  • если он определяет flatMap а также map, это позволяет for-выражения, содержащие из нескольких генераторов.
  • если он определяет foreach, это позволяет for-петли без выхода (как с одиночными, так и с множественными генераторами).
  • если он определяет filter позволяет for - фильтровать выражения, начинающиеся с if в for выражение.

ключевое слово yield в Scala-это просто синтаксический сахар который можно легко заменить на map, а Даниил собрал уже объяснил подробнее.

С другой стороны, yield абсолютно вводит в заблуждение, если вы ищете генераторы (или продолжения), подобные те в Python. См. этот поток SO для получения дополнительной информации:каков предпочтительный способ реализации 'yield' в Scala?

если вы не получите лучшего ответа от пользователя Scala (который я не являюсь), вот мое понимание.

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

что-то типа:

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

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

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

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

рассмотрим следующее понятно

val A = for (i <- Int.MinValue to Int.MaxValue; if i > 3) yield i

может быть полезно прочитать его вслух следующим образом

"на каждое целое число i,если больше 3, потом доходность (произвести) i и добавить его в список A."

С точки зрения математической набор-конструктор нотации выше для понимания аналогично к

set-notation

который может быть прочитан как

"на каждое целое число i,если больше 3, потом является членом комплекса A."

или

"A - это набор всех целых чисел i, таких, что каждый элемент i больше 3."

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, который имеет буфер, который мы не можем видеть, и для каждого приращения он продолжает добавлять следующий элемент в буфер. Когда цикл for завершится, он вернет коллекцию всех полученных значений. Урожай можно использовать как простые арифметические операторы или даже в сочетании с массивами. Вот два простых примера для лучшего понимания

scala>for (i <- 1 to 5) yield i * 3

res: scala.коллекция.неизменный.IndexedSeq[Int] = Вектор(3, 6, 9, 12, 15)

scala> val nums = Seq(1,2,3)
nums: Seq[Int] = List(1, 2, 3)

scala> val letters = Seq('a', 'b', 'c')
letters: Seq[Char] = List(a, b, c)

scala> val res = for {
     |     n <- nums
     |     c <- letters
     | } yield (n, c)

res: Seq [(Int, Char)] = List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))

надеюсь, что это помогает!!

yield является более гибким, чем map (), см. пример ниже

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), что, вероятно, не то, что вы намереваетесь.

Comments

    Ничего не найдено.