카테고리 없음

Scala CH23. for 표현식 다시 보기

ColinKang 2020. 3. 29. 13:22
아래의 글은 마틴 오더스키,렉스 스푼,빌 베너스 공저 / 오현석,이동욱,반영록 공역, 『Programming in Scala 3/e』,에이콘출판사(2017), CH01의 내용을 기반으로 작성하였습니다.

 

persons withFilter (p => !p.isMale) flatMap (p => (p.children map (c => (p.name, c.name))))

 

 

 

 

for (p <- persons; if !p.isMale; c <- p.children)

    yield (p.name, c.name)

스칼라 컴파일러는 for 질의를 위의 질의로 변환함.

 

 

for (p < - persons; n = p.name; if (n startWith "To"))

    yield n

 

 

for {

    p <- persons

    n = p.name

    if (n startWith "To")

} yield n

 

 

for (x < - List(1, 2); y < - List("one", "two))

    yield (x, y)

 

1. for 표현식

for (seq) yield expr

seq는 제네레이터, 정의, 필터 를 나열, 연속된 구성 요소 사이에는 ;를 넣는다.

괄호 대신 중괄호

제네레이터 : pat < - expr : expr 표현식은 보통 리스트를 반환한다

pat 은 그 리스트의 모든 원소를 하나씩 매치해 얻는다

정의 : pat = expr

var x = expr

필터 : if expr

제네레이터가 여러개 있다면 뒤쪽 제네레이터는 앞의 것보다 더 빨리 변화한다.

 

2. 여왕문제

for가 잘 어울리는 경우 combination puzzle 분야

def queens(n: Int) List[List[ (Int, Int) ]] = {

    def placeQueens(k: Int): List[List[(int, Int)]] =

        if (k = 0)

            List(List())

        else

            for {

                queens <- placeQueens(k -1)

                column <- 1 to n

                queen = (k, column)

                if isSafe(queen, queens)

            } yield queen :: queens

    def isSafe(queen: (Int, Int), queens: List[(Int, Int)]) =

        queens forall (q => !inCheck(queen, q))

    def inCheck(q1: (Int, Int), q2: (Int, Int)) =

        q1._1 == q2._1 || // 같은행

        q1._2 == q2._2 || // 같은열

        (q1._1 - q2._2).abs == (q1._2 - q2._2).abs // 대각선

    placeQueens(n)

}

 

3. for 식으로 질의하기

for (b <- books; a <- b.authors)

    if a startWith "Gosling"

yield b.title

 

 

for (b <- books if (b.title indexOf "Program") >= 0)

yield b.title;

 

 

for (b1 <- books; b2 <- books if b1 != b2;

        a1 <- b1.authors; a2 <- b2.authors if a1 == a2)

yield a1

 

 

def removeDuplicates[A](xs : List[A]): List[A] = {

    if (xs.isEmpty) xs

    else

        xs.head :: removeDuplicates (

            xs.tail filter (x => x != xs.head)

        )

}

 

 

xs.head :: removeDuplicates(

    for (x <- xs.tail if x != xs.head) yield x

)

 

4. for 표현식 변환

제네레이터가 하나밖에 없는 for 표현식의 변환

제네레이터로 시작하고 필터가 하나 있는 for 표현식의 변환

제네레이터 2개로 시작하는 for 표현식의 변환

제네레이터 있는 패턴의 변환

정의 변환

for 루프 변환

 

5. 역뱡향 적용

고차함수를 for로 변환

 

6. for 일반화

for 표현식 변환은 오직 map, flatMap, withFilter메소드에만 의존한다.

리스트나 배열 이외엔도 그에 따라 for 표현식이나 루프를 사용할 수 있는 다른 타입이 있음.

range, 이터레이터, 스트림, 모든 집합

사용자 정의 타입도 지원가능한데, map, flatMap, withFilter foreach메소드 구현하면 됨

 

map 만 정의 했다면 제너레이터가 1개만 있는 for 표현식을 사용할 수 있다

map, flatMap을 함께 정의하면 제너레이터가 여러개 있는 for 표현식도 사용 가능

foreach를 정의했다면, for 루프 (제너레이터 개수는 관계없음)을 사용할 수 있다

withFilter를 정의하면 for 표현식 안에 if 로 시작하는 for 필터 표현식을 사용할 수 있다

abstract class C[A] {

    def map[B] (f: A => B): C[B] // 컬렉션의 원소 타입 A에서 다른 타입 B로 매핑하는 함수를 인자로 받는다 그 결과로 같은 유형의 컬렉션 C를 만들지만 원소타입은 B로 바뀐다.

    def flatMap[B] (f: A => c[B]): C[B] // A타입에서 B타입의 원소를 갖는 C 컬렉션으로 매핑하는 함수를 인자로 받아서 B 타입 원소를 갖는 C 컬렉션을 만들어 낸다

    def withFilter(p: A => Boolean): C[A] // 컬렉션의 원소 타입 A를 받아 Boolean 값을 반환하는 술어 함수를 인자로 받는다.

    def foreach(b: A => Unit): Unit // A에서 Unit으로 가는 함수를 인자로 받아서 결과로 Unit을 반환한다

}