Scala CH23. for 표현식 다시 보기
아래의 글은 마틴 오더스키,렉스 스푼,빌 베너스 공저 / 오현석,이동욱,반영록 공역, 『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을 반환한다 }
|