Skip to content

Latest commit

 

History

History
209 lines (152 loc) · 6.29 KB

chapter3.asc

File metadata and controls

209 lines (152 loc) · 6.29 KB

3장 함수형 데이터 구조

3.1. 함수형 데이터구조 정의하기

함수형 데이터 구조는 불변으로 정의하는 것이다.

sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]

object List {
  def sum(ints: List[Int]): Int = ints match {
    case Nil => 0
    case Cons(x: Int, xs: List[Int]) => x + sum(xs)
  }

  def product(ds: List[Double]): Double = ds match {
    case Nil => 1.0
    case Cons(0.0, _) => 0.0
    case Cons(x, xs) => x * product(xs)
  }

  def apply[A](as: A*): List[A] =
    if (as.isEmpty) Nil
    else Cons(as.head, apply(as.tail: _*))
}

트레이트(trait)는 부가적으로 메소드의 구현을 가질 수 있는 추상 인터페이스 이다.
리스트가 비어 있음은 Nil로, 비어있지 않을 때는 Cons로 나타낼 수 있다.

Cons는 초기 요소, head, tail이라고 부르는 리스트의 나머지 요소로 구성된다.
타입 파라미터 A앞에 +는 변동 애노테이션으로 이 기호는 A가 공변성 또는 List의 "가능한" 파라미터 임을 나타내는 것이다.

List[Dog]는 List[Animal]의 서브타입으로 간주된다.

Nil이 List[Nothing]을 상속하는 것에 주목하자. Nothing은 모든 유형의 서브타입이므로 변동 애노테이션과 함께 Nil은 정확하게 List [Int], List [Double] 등으로 간주 될 수 있다.

3.2. 패턴 매칭

동반 객체(companion object) class나 trait와 동일한 이름을 사용하는 객체이고, 동일한 소스 파일에 정의된다. 동반 객체는 다른 객체는 접근할 수 없지만 적절한 class/trait에는 접근할 수 있어서 다른 객체와는 차이점이 있다. 특히 class/trait의 private 필드나 메소드에 접근할 수 있다.

class A(d: String) {
  private var a = ""
  override def toString = d + a;
}

object A {
  def apply(b:String, e:String) = {
    val a = new A(b)
    a.a = e
    a
  }
}
case class B()
object B {
  def apply() = {
    val a = new A("")
    //can not access a.a
    new B()
  }
}

패턴 매치는 표현식의 구조로 내려갈 수있는 멋진 switch 문처럼 작동하여 해당 구조의 하위 표현식을 검사하고 추출한다.

  1. List(1,2,3) match { case _ ⇒ 42 } 결과는 42. 변수 패턴으로 매치한 것으로 _는 어떤 표현식과도 매치된다.

  2. List(1,2,3) match { case Cons(h,_) ⇒ h } 결과는 1

  3. List(1,2,3) match { case Cons(_,t) ⇒ t } 결과는 List(2,3)

  4. List(1,2,3) match { case Nil ⇒ 42 } 결과는 실행시 MatchError 를 발생한다. MatchError는 매치 표현식에서 타겟에 매치된 것이 없을 때를 나타낸다.

객체의 리스트를 적용하는 함수를 variadic 함수라 하고, 0개 또는 더 많은 A타입의 매개변수를 설정할 수 있다 특별한 타입 애노테이션 _*은 variadic method로 Seq를 전달 할 수 있도록 한다.

3.3 함수적 자료구조의 자료 공유

자료공유(data sharing)

실제 자료는 불변(immutuable). 복사나 수정없이 목록 자료를 재사용하면 된다. 자료구조에 연산이 가해져도 기존 참조들은 변하지 않는다.

함수적 자료구조는 영속적(persistent)

	head -> (a, link) -> (b, link) -> (c, link) -> (d, Nil)


	val first = head
			=>	List(a, b, c, d)
	val second = head.link
			=>	List(b, c, d)

3.3.1 자료 공유의 효율성

효율적인 예
def append[A](a1: List[A], a2: List[A]): List[A] =
	a1 match {
		case Nil => a2
		case Cons(h,t) => Cons(h, apeend(t, a2))
	}

해석 : 현재 함수의 실행 시간과 메모리 사용량은 오직 a1의 길이에 의존. 이후는 단순 a2를 가르킨다.

비효율적인 예
def init[A](l: List[A]): List[A] = {
	l match {
		case Cons(h, Nil) => Nil
		case Cons(h, t) => Cons(h, init(t))
	}
}

해석 : Cons의 tail 을 치환할 때마다 반드시 이전의 모든 Cons 객체를 복사해야 한다.

3.3.2 고차 함수를 위한 형식 추론 개선

정의
	def dropWhile[A](l: List[A], f: A => Boolean): List[A]
	dropWhile(xs, (x: Int) => x < 4)
	=> x 의 parameter 정의가 필요함.
새롭게 정의
	def dropWhile[A](as: List[A])(f: A => Boolean): List[A]
	(using curring)
	=> dropWhile(xs)(x => x < 4)

	(dropWhile(xs))(x => x < 4)
	(result)(x => x < 4)

해석 : result 에서 generic A 가 이미 정의되었음.

3.4 목록에 대한 재귀와 고차 함수로의 일반화

	def foldRight[A, B](as: List[A], z: B)(f: (A, B) => B): B =
		as match {
			case Nil => z
			case Cons(x, xs) => f(x, fildRight(xs, z)(f))
		}

	def sum2(ns: List[Int]) =
		foldRight(ns, 0)((x,y) => x + y)

	def product2(ns: List[Double]) =
		foldRight(ns, 1.0)(_ * _)

3 함수적 자료구조

3.4 목록에 대한 재귀와 고차 함수로의 일반화

3.4.1 그 외의 목록 조작 함수들

표준 라이브러리의 List

1

2 :: Nil == 1 :: (2 :: Nil) == List(1,2)

표준 라이브러리의 목록

  • def take(n: Int): List[A] this의 처음 n개의 요소들로 이루어진 목록을 돌려준다.

  • def takeWhile(f: A ⇒ Boolean): List[A] 주어진 술어 f를 만족하는, this의 가장 긴 선행 요소들로 이루어진 목록을 돌려준다.

  • def forall(f: A ⇒ Boolean): Boolean this의 모든 요소가 술어 f를 만족할 때에만 true를 돌려준다.

  • def exists(f: A ⇒ Boolean): Boolean this의 요소들 중 하나라도 f를 만족하는 것이 있으면 true를 돌려준다.

  • scanLeft와 scanRight foldLeft 및 foldRight와 비슷하되 최종적으로 누적된 값만 돌려주는 것이 아니라 부분 결과들의 List를 돌려준다.

3.4.2 단순 구성요소들로 목록 함수를 조립할 때의 효율성 손실

List의 문제점 (효율성 손)

  • 같은 입력을 여러 번 훑는 구현이 만들어질 수 있다.

  • 이른 종료를 위해 명시적인 재귀 루프를 작성해야 할 수 있다.

3.5 트리

대수적 자료형식(algebraic data type, ADT)

  • ex) List, Tree

  • 하나 이상의 자료 생성자들로 이루어진 자료 형식

  • 0개 이상의 인수를 받을 수 있음

  • 자료 형식: 자료 생성자들의 합(sum), 합집합(union)

  • 자료 생성자: 인수들의 곱(product)

트리

소스 참고