[scala] 스칼라의 수확량은 얼마입니까?

나는 루비와 파이썬의 수율을 이해합니다. 스칼라의 수확량은 무엇입니까?



답변

그것은에서 사용되는 시퀀스 함축 (당신이 사용할 수 파이썬의리스트 지능형 발전기처럼 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. 스칼라는 실제로 for-expression을 해당 메소드에 대한 호출로 변환 하므로이를 제공하는 클래스 또는 서브 세트를 이해하기 위해 사용할 수 있습니다.

먼저 번역에 대해 이야기합시다. 매우 간단한 규칙이 있습니다.

  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 {...}

    스칼라 2.7에서

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

    스칼라 2.8에서

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

    방법을 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방법은 컬렉션의 엄격성에 따라 동작이 정의됩니다. 이것을 더 잘 이해하려면 List(엄격한) 및 Stream(엄격하지 않은 ) 스칼라 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

때문에 차이가 발생하는 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사전에 전체 컬렉션에 적용되는 대신 주문형으로 간주 되기 때문에 많은 문제가 발생 했습니다.

도입 스칼라 2.8 withFilter입니다, 항상 비 엄격한은 더 컬렉션의 엄격 상관 없습니다. 다음 예제는 ListScala 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동작 을 바꾸지 않고 대부분의 사람들이 기대하는 결과를 만들어냅니다 . 참고로 RangeScala 2.7과 Scala 2.8 사이에서 엄격하지 않음에서 엄격으로 변경되었습니다.


답변

예, Earwicker가 말했듯이 LINQ select와 거의 동일 하며 Ruby 및 Python과 거의 관련이 없습니다 yield. 기본적으로 C #에서 작성하는 위치

from ... select ??? 

스칼라에서는 대신에

for ... yield ???

for-comprehensions는 시퀀스에서만 작동하는 것이 아니라 LINQ와 같이 특정 메소드를 정의하는 모든 유형에서 작동 한다는 것을 이해하는 것이 중요합니다 .

  • 유형이 just을 정의 하면 단일 생성기로 구성된 표현식 map을 허용 for합니다.
  • flatMap뿐만 아니라를 정의 map하면 for여러 생성기로 구성된 표현식 을 허용 합니다.
  • 로 정의 foreach하면 for수율없이 단일 루프와 다중 생성기를 사용하여 -loops를 허용 합니다.
  • 이 정의하는 경우 filter, 그것은 수 for로 시작 -filter 표현 if
    for표현.

답변

Scala 사용자로부터 더 나은 답변을 얻지 못하면 (내가 아님), 여기 내 이해가 있습니다.

for기존 목록에서 새 목록을 생성하는 방법을 나타내는으로 시작하는 표현식의 일부로 만 나타납니다 .

다음과 같은 것 :

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

따라서 각 입력에 대해 하나의 출력 항목이 있습니다 (중복을 삭제하는 방법이 있다고 생각하지만).

이것은 거의 모든 구조를 가진 일부 명령 코드에서 길이의 목록을 생성하는 방법을 제공하는 다른 언어의 yield로 활성화 된 “제한 연속”과는 매우 다릅니다.

(C #에 익숙하다면 LINQ select 연산자보다 LINQ 연산자에 더 가깝 습니다 yield return).


답변

키워드 yield스칼라는 단순히 문법 설탕입니다 쉽게 교체 할 수 있습니다 map로, 다니엘 소브랄 이미 설명 자세히.

반면에, yield절대적 경우 오해의 소지가있다 파이썬 과 유사한 생성기 (또는 연속체)를 찾고 . 자세한 내용은이 SO 스레드를 참조하십시오. Scala에서 ‘수율’을 구현하는 기본 방법은 무엇입니까?


답변

다음과 같은 이해력을 고려하십시오

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

다음과 같이 큰 소리로 읽는 것이 도움이 될 수 있습니다

위해 각각의 정수 i, 만약 그것보다 큰 3수율 (생산) i과 목록에 추가A .”

수학적 set-builder 표기법 측면 에서 위의 이해력은 다음과 유사합니다.

세트 표기

로 읽을 수 있습니다

위해 각각의 정수 나는, 만약 그것보다 크면 삼, 그것은 구성원 세트 중 ㅏ.”

또는 대안으로

ㅏ는 모든 정수의 집합 나는이므로 각각 나는이보다 큽니다 삼.”


답변

수율은 우리가 볼 수없는 버퍼를 가지고 있고 각 증가마다 버퍼에 다음 항목을 계속 추가하는 for 루프와 유사합니다. for 루프가 실행을 마치면 생성 된 모든 값의 컬렉션을 반환합니다. 수율은 간단한 산술 연산자로 사용하거나 배열과 함께 사용할 수도 있습니다. 이해를 돕기위한 두 가지 간단한 예가 있습니다.

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

입술 : scala.collection.immutable.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)] =리스트 ((1, a), (1, b), (1, c), (2, a), (2, b), (2, c), ( 3, a), (3, b), (3, c))

도움이 되었기를 바랍니다!!