본문으둜 κ±΄λ„ˆλ›°κΈ°

🍭 Chapter 3: ν•¨μˆ˜μ  자료ꡬ쑰

πŸŽƒ ν•¨μˆ˜μ  자료ꡬ쑰의 μ˜λ―Έβ€‹

ν•¨μˆ˜μ  μžλ£Œκ΅¬μ‘°λž€ 였직 순수 ν•¨μˆ˜λ§ŒμœΌλ‘œ μ‘°μž‘λ˜λŠ” μžλ£Œκ΅¬μ‘°μ΄λ‹€. 순수 ν•¨μˆ˜λŠ” 자료λ₯Ό κ·Έ μžλ¦¬μ—μ„œ λ³€κ²½ν•˜κ±°λ‚˜ 기타 λΆ€μˆ˜ 효과λ₯Ό μˆ˜ν–‰ν•˜λŠ” 일이 μ—†μ–΄μ•Ό 함을 κΈ°μ–΅ν•˜κΈ° λ°”λž€λ‹€. λ”°λΌμ„œ ν•¨μˆ˜μ  μžλ£Œκ΅¬μ‘°λŠ” μ •μ˜μ— μ˜ν•΄ λΆˆλ³€μ΄λ‹€.

κ°€μž₯ 보변적인 ν•¨μˆ˜μ  자료ꡬ쑰라 ν•  수 μžˆλŠ” 단일 μ—°κ²° λͺ©λ‘μ„ μ‚΄νŽ΄λ³΄μž. λ‹€μŒμ˜ 단일 μ—°κ²° λͺ©λ‘ μ •μ˜λŠ” 사싀상 슀칼라의 ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬μ— μ •μ˜λ˜μ–΄ μžˆλŠ” List 자료 ν˜•μ‹μ˜ 것과 κ°œλ…μ μœΌλ‘œ λ™μΌν•˜λ‹€.

package fpinscala.datastructures

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, xs) => 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 ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•œλ‹€. trait ν‚€μ›Œλ“œλ‘œ μ •μ˜ν•˜λŠ” 특질(trait)은 ν•˜λ‚˜μ˜ 좔상 μΈν„°νŽ˜μ΄μŠ€λ‘œ, ν•„μš”ν•˜λ‹€λ©΄ 일뢀 λ©”μ„œλ“œμ˜ κ΅¬ν˜„μ„ 담을 μˆ˜λ„ μžˆλ‹€. μ§€κΈˆ μ˜ˆμ—μ„œλŠ” traitλ₯Ό μ΄μš©ν•΄μ„œ ListλΌλŠ” νŠΉμ§ˆμ„ μ •μ˜ν•œλ‹€. 이 νŠΉμ§ˆμ—λŠ” λ©”μ„œλ“œκ°€ ν•˜λ‚˜λ„ μ—†λ‹€. trait μ•žμ— sealedλ₯Ό λΆ™μ΄λŠ” 것은 이 특질의 λͺ¨λ“  κ΅¬ν˜„μ΄ λ°˜λ“œμ‹œ 이 파일 μ•ˆμ— μ„ μ–Έλ˜μ–΄ μžˆμ–΄μ•Ό 함을 λœ»ν•œλ‹€.

κ·Έ λ‹€μŒμ—λŠ” μžˆλŠ” case ν‚€μ›Œλ“œλ‘œ μ‹œμž‘ν•˜λŠ” 두 쀄은 List의 두 가지 κ΅¬ν˜„, 즉 두 가지 자료 μƒμ„±μžμ΄λ‹€. ListλŠ” 자료 μƒμ„±μž Nil둜 ν‘œκΈ°λ˜λŠ” 빈 λͺ©λ‘μΌ μˆ˜λ„ 있고 자료 μƒμ„±μž Cons(관둀상 constructor의 μ€„μž„λ§λ‘œ 쓰인닀)둜 ν‘œκΈ°λ˜λŠ” 비지 μ•Šμ€ λͺ©λ‘μΌ μˆ˜λ„ μžˆλ‹€. 비지 μ•Šμ€ λͺ©λ‘μ€ 초기 μš”μ†Œ head λ‹€μŒμ— λ‚˜λ¨Έμ§€ μš”μ†Œλ“€μ„ 담은 ν•˜λ‚˜μ˜ List둜 κ΅¬μ„±λœλ‹€.

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

ν•¨μˆ˜λ₯Ό λ‹€ν˜•μ μœΌλ‘œ λ§Œλ“€ 수 μžˆλ“―μ΄, 자료 ν˜•μ‹λ„ λ‹€ν˜•μ μœΌλ‘œ λ§Œλ“€ 수 μžˆλ‹€. sealed trait List λ‹€μŒμ— ν˜•μ‹ λ§€κ°œλ³€μˆ˜ [+A]λ₯Ό 두고 Cons 자료 μƒμ„±μž μ•ˆμ—μ„œ κ·Έ A λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•¨μœΌλ‘œμ¨, λͺ©λ‘μ— λ‹΄κΈ΄ μš”μ†Œλ“€μ˜ ν˜•μ‹μ— λŒ€ν•΄ λ‹€ν˜•μ„±μ΄ μ μš©λ˜λŠ” List 자료 ν˜•μ‹μ΄ λ§Œλ“€μ–΄μ§„λ‹€. 그러면 ν•˜λ‚˜μ˜ λ™μΌν•œ μ •μ˜λ‘œ Int μš”μ†Œλ“€μ˜ λͺ©λ‘, Double μš”μ†Œλ“€μ˜ λͺ©λ‘, String μš”μ†Œλ“€μ˜ λͺ©λ‘ 등등을 μ‚¬μš©ν•  수 있게 λœλ‹€(ν˜•μ‹ 맀개 λ³€μˆ˜ A에 μžˆλŠ” +λŠ” 곡변을 λœ»ν•œλ‹€).

자료 μƒμ„±μž 선언은 ν•΄λ‹Ή ν˜•νƒœμ˜ 자료 ν˜•μ‹μ„ κ΅¬μΆ•ν•˜λŠ” ν•¨μˆ˜λ₯Ό λ„μž…ν•œλ‹€. λ‹€μŒμ€ 자료 μƒμ„±μžμ˜ 용레 λͺ‡ 가지이닀.

val ex1: List[Double] = Nil
val ex2: List[Int] = Cons(1, Nil)
val ex3: List[String] = Cons("a", Cons("b", Nil))

case object Nil에 μ˜ν•΄ Nilμ΄λΌλŠ” ν‘œκΈ°λ₯Ό μ΄μš©ν•΄μ„œ 빈 Listλ₯Ό ꡬ좕할 수 있게 되며, case class ConsλŠ” Cons(1, Nil), Cons("a", Cons("b", Nil)) 같은 ν‘œκΈ°λ₯Ό ν†΅ν•΄μ„œ μž„μ˜μ˜ 길이의 단일 μ—°κ²° λͺ©λ‘μ„ ꡬ좕할 수 있게 ν•œλ‹€. ListλŠ” ν˜•μ‹ A에 λŒ€ν•΄ λ§€κ°œλ³€μˆ˜ν™”λ˜μ–΄ μžˆμœΌλ―€λ‘œ, 이 ν•¨μˆ˜λ“€ μ—­μ‹œ μ„œλ‘œ λ‹€λ₯Έ ν˜•μ‹μ˜ A에 λŒ€ν•΄ μΈμŠ€ν„΄μŠ€ν™”λ˜λŠ” λ‹€ν˜•μ  ν•¨μˆ˜λ“€μ΄λ‹€.

각 자료 μƒμ„±μžλŠ” sumμ΄λ‚˜ product 같은 ν•¨μˆ˜λ“€μ—μ„œμ²˜λŸΌ νŒ¨ν„΄ λΆ€ν•©(pattern matching)에 μ‚¬μš©ν•  수 μžˆλŠ” νŒ¨ν„΄λ„ λ„μž…ν•œλ‹€.

πŸŽƒ νŒ¨ν„΄ 뢀합​

object List에 μ†ν•œ ν•¨μˆ˜ sumκ³Ό productλ₯Ό μžμ„Ένžˆ μ‚΄νŽ΄λ³΄μž. 이런 ν•¨μˆ˜λ“€μ€ List의 λ™λ°˜ 객체(companion object)라고 λΆ€λ₯΄κΈ°λ„ ν•œλ‹€. 두 ν•¨μˆ˜ λͺ¨λ‘ νŒ¨ν„΄ 뢀합을 ν™œμš©ν•œλ‹€.

def sum(ints: List[Int]): Int = ints match {
case Nil => 0
case Cons(x, xs) => 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)
}

이듀이 μž¬κ·€μ μΈ μ •μ˜μž„μ„ μ£Όλͺ©ν•˜κΈ° λ°”λž€λ‹€. List 같은 μž¬κ·€μ μΈ 자료 ν˜•μ‹μ„ λ‹€λ£¨λŠ” ν•¨μˆ˜λ“€μ„ μž‘μ„±ν•  λ•ŒλŠ” 이처럼 μž¬κ·€μ μΈ μ •μ˜λ₯Ό μ‚¬μš©ν•˜λŠ” κ²½μš°κ°€ λ§Žλ‹€.

νŒ¨ν„΄ 뢀합은 ν‘œν˜„μ‹μ˜ ꡬ쑰λ₯Ό 따라 λ‚΄λ €κ°€λ©΄μ„œ κ·Έ ꡬ쑰의 λΆ€λΆ„ ν‘œν˜„μ‹μ„ μΆ”μΆœν•˜λŠ” λ³΅μž‘ν•œ switch λ¬Έκ³Ό λΉ„μŠ·ν•˜κ²Œ μž‘λ™ν•œλ‹€. λΆ€ν•©μ˜ 각 경우 문은 => 의 μ’Œλ³€μ— νŒ¨ν„΄μ΄ 있고 κ·Έ μš°λ³€μ— κ²°κ³Όκ°€ μžˆλŠ” ν˜•νƒœμ΄λ‹€. λŒ€μƒμ˜ 경우 문의 νŒ¨ν„΄κ³Ό λΆ€ν•©ν•˜λ©΄, κ·Έ 경우 문의 κ²°κ³Όκ°€ 전체 λΆ€ν•© ν‘œν˜„μ‹μ˜ κ²°κ³Όκ°€ λœλ‹€. 만일 λŒ€μƒκ³Ό λΆ€ν•©ν•˜λŠ” νŒ¨ν„΄μ΄ μ—¬λŸ¬ 개면 μŠ€μΉΌλΌλŠ” 처음으둜 λΆ€ν•©ν•˜λŠ” 경우 문을 μ„ νƒν•œλ‹€.

πŸŽƒ ν•¨μˆ˜μ  자료ꡬ쑰의 자료 κ³΅μœ β€‹

μžλ£Œκ°€ λΆˆλ³€μ΄λΌλ©΄, 예λ₯Ό λ“€μ–΄ λͺ©λ‘μ— μš”μ†Œλ₯Ό μΆ”κ°€ν•˜κ±°λ‚˜ λͺ©λ‘μ—μ„œ μš”μ†Œλ₯Ό μ œκ±°ν•˜λŠ” ν•¨μˆ˜λŠ” μ–΄λ–»κ²Œ μž‘μ„±ν•΄μ•Ό ν• κΉŒ? κΈ°μ‘΄ λͺ©λ‘μ˜ μ•žμ— 1μ΄λΌλŠ” μš”μ†Œλ₯Ό μΆ”κ°€ν•˜λ €λ©΄ Cons(1, xs)λΌλŠ” μƒˆ λͺ©λ‘μ„ λ§Œλ“€λ©΄ λœλ‹€. λͺ©λ‘μ€ λΆˆλ³€μ΄λ―€λ‘œ xsλ₯Ό μ‹€μ œλ‘œ 볡사할 ν•„μš”λŠ” μ—†λ‹€. κ·Έλƒ₯ μž¬μ‚¬μš©ν•˜λ©΄ λœλ‹€. 이λ₯Ό 자료 곡유라고 λΆ€λ₯Έλ‹€. λΆˆλ³€μ΄ 자료λ₯Ό κ³΅μœ ν•˜λ©΄ ν•¨μˆ˜λ₯Ό μ’€ 더 효율적으둜 κ΅¬ν˜„ν•  수 μžˆμ„ λ•Œκ°€ λ§Žλ‹€. μžλ£Œκ°€ λ³€ν•˜κ±°λ‚˜ 깨지지 μ•Šλ„λ‘ λ°©μ–΄μ μœΌλ‘œ 볡사본을 λ§Œλ“€μ–΄ λ‘˜ ν•„μš”κ°€ μ—†λŠ” 것이닀.

이λ₯Ό 두고 ν•¨μˆ˜μ  μžλ£Œκ΅¬μ‘°λŠ” μ˜μ†μ (persistent)이라고 λ§ν•œλ‹€. μ΄λŠ” μžλ£Œκ΅¬μ‘°μ— 연산이 가해져도 기쑴의 참쑰듀이 κ²°μ½” λ³€ν•˜μ§€ μ•ŠμŒμ„ λœ»ν•œλ‹€.

🎈 자료 곡유의 νš¨μœ¨μ„±β€‹

자료 곡유λ₯Ό μ΄μš©ν•˜λ©΄ 연산을 μ’€ 더 효율적으둜 μˆ˜ν–‰ν•  수 μžˆλŠ” κ²½μš°κ°€ λ§Žλ‹€. 자료 곡유의 λ”μš± λ†€λΌλŠ” 예둜, λ‹€μŒ ν•¨μˆ˜λŠ” ν•œ λͺ©λ‘μ˜ λͺ¨λ“  μš”μ†Œλ₯Ό λ‹€λ₯Έ λͺ©λ‘μ˜ 끝에 μΆ”κ°€ν•œλ‹€.

def append[A](a1: List[A], a2: List[A]): List[A] =
a1 match {
case Nil => a2
case Cons(h, t) => Cons(h, append(t, a2))
}

이 μ •μ˜λŠ” 였직 첫 λͺ©λ‘μ΄ λ‹€ μ†Œμ§„λ  λ•ŒκΉŒμ§€λ§Œ 값듀을 볡사함을 μ£Όμ˜ν•˜κΈ° λ°”λž€λ‹€. λ”°λΌμ„œ 이 ν•¨μˆ˜μ˜ μ‹€ν–‰ μ‹œκ°„κ³Ό λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰μ€ 였직 a1의 κΈΈμ΄μ—λ§Œ μ˜μ‘΄ν•œλ‹€. λͺ©λ‘μ˜ λ‚˜λ¨Έμ§€λŠ” κ·Έλƒ₯ a2λ₯Ό 가리킬 뿐이닀. 만일 이 ν•¨μˆ˜λ₯Ό λ°°μ—΄ 두 개λ₯Ό μ΄μš©ν•΄μ„œ κ΅¬ν˜„ν•œλ‹€λ©΄ 두 λ°°μ—΄μ˜ λͺ¨λ“  μš”μ†Œλ₯Ό κ²°κ³Ό 배열에 볡사해야 ν–ˆμ„ 것이닀. 이 경우 λΆˆλ³€μ΄ μ—°κ²° λͺ©λ‘μ΄ 배열보닀 훨씬 νš¨μœ¨μ μ΄λ‹€.

단일 μ—°κ²° λͺ©λ‘μ˜ ꡬ쑰 λ•Œλ¬Έμ—, Cons의 tail의 μΉ˜ν™˜ν•  λ•Œλ§ˆλ‹€ λ°˜λ“œμ‹œ μ΄μ „μ˜ λͺ¨λ“  Cons 객체λ₯Ό 볡사해야 ν•œλ‹€. μ„œλ‘œ λ‹€λ₯Έ 연산듀을 효율적으둜 μ§€μ›ν•˜λŠ” 순수 ν•¨μˆ˜μ  자료ꡬ쑰λ₯Ό μž‘μ„±ν•  λ•Œμ˜ 관건은 자료 곡유λ₯Ό ν˜„λͺ…ν•˜κ²Œ ν™œμš©ν•˜λŠ” 방법을 μ°Ύμ•„λ‚΄λŠ” 것이닀. (슀칼라 ν‘œμ€€ 라이브러리의 순수 ν•¨μˆ˜μ  μˆœμ°¨μ—΄ κ΅¬ν˜„μΈ Vectorλ₯Ό μ°Έκ³ )

🎈 κ³ μ°¨ ν•¨μˆ˜λ₯Ό μœ„ν•œ ν˜•μ‹ μΆ”λ‘  κ°œμ„ β€‹

dropWhile 같은 κ³ μ°¨ ν•¨μˆ˜μ—λŠ” ν”νžˆ 읡λͺ… ν•¨μˆ˜λ₯Ό λ„˜κ²¨μ€€λ‹€. 그럼 μ „ν˜•μ μΈ 예λ₯Ό ν•˜λ‚˜ 보자. μš°μ„  dropWhile의 μ„œλͺ…을 λ– μ˜¬λ €λ³΄μž.

def dropWhile[A](l: List[A], f: A => Boolean): List[A]

인수 f에 읡λͺ… ν•¨μˆ˜λ₯Ό μ§€μ •ν•΄μ„œ ν˜ΈμΆœν•˜κΈ° μœ„ν•΄μ„œλŠ” κ·Έ 읡λͺ… ν•¨μˆ˜μ˜ 인수의 ν˜•μ‹μ„ λͺ…μ‹œν•΄μ•Ό ν•œλ‹€.

val xs: List[int] = List(1,2,3,4,5)
val ex1 = dropWhile(xs, (x: Int) => x < 4)
// List(4,5)

x의 ν˜•μ‹μ΄ Intμž„μ„ λͺ…μ‹œμ μœΌλ‘œ ν‘œκΈ°ν•΄μ•Ό ν•œλ‹€λŠ” 것은 λ‹€μ†Œ λ²ˆκ±°λ‘­λ‹€. dropWhile의 첫 μΈμˆ˜λŠ” List[Int]μ΄λ―€λ‘œ, λ‘˜μ§Έ 인수의 ν•¨μˆ˜λŠ” λ°˜λ“œμ‹œ Intλ₯Ό λ°›μ•„μ•Ό ν•œλ‹€. λ‹€μŒμ²˜λŸΌ dropWhile의 μΈμˆ˜λ“€μ„ 두 그룹으둜 묢으면 μŠ€μΉΌλΌκ°€ κ·ΈλŸ¬ν•œ 사싀을 μΆ”λ‘ ν•  수 μžˆλ‹€.

def dropWhile[A](as: List[A])(f: A => Boolean): List[A] =
as match {
case Cons(h, t) if f(h) => dropWhile(t)(f)
case _ => as
}

이 버전은 dropWhile을 ν˜ΈμΆœν•˜λŠ” ꡬ문은 dropWhile(xs)(f)의 ν˜•νƒœμ΄λ‹€. 즉, dropWhile(xs)λŠ” ν•˜λ‚˜μ˜ ν•¨μˆ˜λ₯Ό 돌렀주며, κ·Έ ν•¨μˆ˜λ₯Ό 인수 f둜 ν˜ΈμΆœν•œλ‹€. μΈμˆ˜λ“€μ„ 이런 μ‹μœΌλ‘œ λ¬ΆλŠ” 것은 슀칼라의 ν˜•μ‹ 좔둠을 돕기 μœ„ν•œ 것이닀. μ΄μ œλŠ” dropWhile을 λ‹€μŒκ³Ό 같이 ν˜•μ‹ μ£Όν•΄ 없이 ν˜ΈμΆœν•  수 μžˆλ‹€.

val xs: List[Int] = List(1,2,3,4,5)
val ex1 = dropWhile(xs)(x => x < 4)

x의 ν˜•μ‹μ„ λͺ…μ‹œμ μœΌλ‘œ μ§€μ •ν•˜μ§€ μ•Šμ•˜μŒμ„ μ£Όλͺ©ν•˜κΈ° λ°”λž€λ‹€.

μ’€ 더 μΌλ°˜ν™”ν•˜μžλ©΄, ν•¨μˆ˜ μ •μ˜μ— μ—¬λŸ¬ 개의 인수 그룹이 μ‘΄μž¬ν•˜λŠ” 경우 ν˜•μ‹ μ •λ³΄λŠ” κ·Έ 인수 그룹듀을 따라 μ™Όμͺ½μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ ν˜λŸ¬κ°„λ‹€. 이처럼, ν˜•μ‹ 좔둠이 μ΅œλŒ€λ‘œ μΌμ–΄λ‚˜λ„λ‘ ν•¨μˆ˜ μΈμˆ˜λ“€μ„ μ μ ˆν•œ μˆœμ„œμ˜ μ—¬λŸ¬ 인수 λͺ©λ‘μ„ λ¬ΆλŠ” κ²½μš°κ°€ λ§Žλ‹€.

πŸŽƒ λͺ©λ‘μ— λŒ€ν•œ μž¬κ·€μ™€ κ³ μ°¨ ν•¨μˆ˜λ‘œμ˜ μΌλ°˜ν™”β€‹

sumκ³Ό product의 κ΅¬ν˜„μ„ λ‹€μ‹œ μ‚΄νŽ΄λ³΄μž.

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

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

두 μ •μ˜κ°€ μ•„μ£Ό λΉ„μŠ·ν•˜λ‹€λŠ” 점에 μ£Όλͺ©ν•˜μž. 이런 μ½”λ“œ 쀑볡을 λ°œκ²¬ν–ˆλ‹€λ©΄ λΆ€λΆ„ ν‘œν˜„μ‹λ“€μ„ μΆ”μΆœν•΄μ„œ ν•¨μˆ˜ 인수둜 λŒ€μ²΄ν•¨μœΌλ‘œμ¨ μ½”λ“œλ₯Ό μΌλ°˜ν™”ν•˜λŠ” 것이 항상 κ°€λŠ₯ν•˜λ‹€. μΌλ°˜ν™”λœ ν•¨μˆ˜λŠ” 빈 λͺ©λ‘μΌ λ•Œμ˜ λ°˜ν™˜κ°’κ³Ό 비지 μ•Šμ€ λͺ©λ‘μΌ λ•Œ 결과에 μš”μ†Œλ₯Ό μΆ”κ°€ν•˜λŠ” ν•¨μˆ˜λ₯Ό 인수둜 λ°›λŠ”λ‹€.

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, foldRight(xs, z)(f))
}

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

def product2(ns: List[Double]) =
foldRight(ns, 1.0)(_ * _) // (x, y) => x * yλ₯Ό μ’€ 더 κ°„κ²°ν•˜κ²Œ ν‘œκΈ°ν•œ 것이닀.

foldRightλŠ” ν•˜λ‚˜μ˜ μš”μ†Œ ν˜•μ‹μ—λ§Œ νŠΉν™”λ˜μ§€ μ•Šμ•˜λ‹€. 그리고 μΌλ°˜ν™” κ³Όμ •μ—μ„œ μš°λ¦¬λŠ” 이 ν•¨μˆ˜κ°€ λŒλ €μ£ΌλŠ” 값이 λͺ©λ‘μ˜ μš”μ†Œμ™€ 같은 ν˜•μ‹μΌ ν•„μš”κ°€ μ—†λ‹€λŠ” 점도 μ•Œκ²Œ λ˜μ—ˆλ‹€. foldRightκ°€ ν•˜λŠ” 일을 이런 μ‹μœΌλ‘œ μ„€λͺ…ν•  수 μžˆλ‹€: 이 ν•¨μˆ˜λŠ” λ‹€μŒμ—μ„œ 보듯이 λͺ©λ‘μ˜ μƒμ„±μž Nilκ³Ό Consλ₯Ό z와 f둜 μΉ˜ν™˜ν•œλ‹€.

Cons(1, Cons(2, Nil))
f(1, f(2, z))

foldRightκ°€ ν•˜λ‚˜μ˜ κ°’μœΌλ‘œ μΆ•μ•½λ˜λ €λ©΄ λ°˜λ“œμ‹œ λͺ©λ‘μ˜ λκΉŒμ§€ μˆœνšŒν•΄μ•Ό 함을 μ£Όλͺ©ν•˜κΈ° λ°”λž€λ‹€.

🎈 κ·Έ μ™Έμ˜ λͺ©λ‘ μ‘°μž‘ ν•¨μˆ˜λ“€β€‹

λͺ©λ‘μ„ μ²˜λ¦¬ν•˜λŠ” ν•¨μˆ˜λ₯Ό μž‘μ„±ν•  λ•ŒλŠ” λͺ…μ‹œμ μΈ μž¬κ·€ ν•¨μˆ˜λ₯Ό μΌλ°˜ν™”ν•˜λŠ” μ—¬λŸ¬ 방법을 κ³ λ €ν•΄ λ³΄λŠ” μŠ΅κ΄€μ„ 가지길 λ°”λž€λ‹€. κ·Έλ ‡κ²Œ ν•˜λ©΄ 이런 ν•¨μˆ˜λ“€μ„ 슀슀둜 (재)λ°œκ²¬ν•˜κ²Œ 될 것이며, κ·ΈλŸ¬λ‹€ 보면 각각의 μ μ ˆν•œ μš©λ„λ₯Ό λ³ΈλŠ₯적으둜 μ•Œκ²Œ 될 것이닀.

ν‘œμ€€ 라이브러리의 λͺ©λ‘λ“€β€‹

슀칼라 ν‘œμ€€ 라이브러리(API λ¬Έμ„œν™”λŠ” http://mng.bz/vu45)에도 Listκ°€ μžˆλ‹€.

ν‘œμ€€ 라이브러리의 λͺ©λ‘μ—λŠ” 이외에도 μ—¬λŸ¬ 가지 μœ μš©ν•œ λ©”μ„œλ“œκ°€ μžˆλ‹€. μ§€κΈˆκΉŒμ§€ λ³Έ λ©”μ„œλ“œλ“€κ³Ό 달리 이듀은 독립적인 ν•¨μˆ˜κ°€ μ•„λ‹ˆλΌ List[A]의 λ©”μ„œλ“œλ‘œ μ •μ˜λ˜μ–΄ μžˆλ‹€.

  • 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λ₯Ό λŒλ €μ€€λ‹€.

🎈 λ‹¨μˆœ κ΅¬μ„±μš”μ†Œλ“€λ‘œ λͺ©λ‘ ν•¨μˆ˜λ₯Ό 쑰립할 λ•Œμ˜ νš¨μœ¨μ„± 손싀​

List의 ν•œ 가지 λ¬Έμ œλŠ”, μ–΄λ–€ μ—°μ‚°μ΄λ‚˜ μ•Œκ³ λ¦¬μ¦˜μ„ μ•„μ£Ό λ²”μš©μ μΈ ν•¨μˆ˜λ“€λ‘œ ν‘œν˜„ν•  수 있긴 ν•˜μ§€λ§Œ κ·Έ 결과둜 λ§Œλ“€μ–΄μ§„ κ΅¬ν˜„μ΄ 항상 νš¨μœ¨μ μ΄μ§€λŠ” μ•ŠλŠ”λ‹€λŠ” 점이닀. 같은 μž…λ ₯을 μ—¬λŸ¬ 번 ν›‘λŠ” κ΅¬ν˜„μ΄ λ§Œλ“€μ–΄μ§ˆ 수 있으며, 이λ₯Έ μ’…λ£Œλ₯Ό μœ„ν•΄μ„œλŠ” λͺ…μ‹œμ μΈ μž¬κ·€ 루푸λ₯Ό μž‘μ„±ν•΄μ•Ό ν•  수 μžˆλ‹€.

πŸŽƒ νŠΈλ¦¬β€‹

ListλŠ” μ†Œμœ„ λŒ€μˆ˜μ  자료 ν˜•μ‹(algebraic data tye, ADT)이라고 λΆ€λ₯΄λŠ” κ²ƒμ˜ ν•œ 예일 뿐이닀. (이 ADTλ₯Ό λ‹€λ₯Έ λΆ„μ•Όμ—μ„œ λ§ν•˜λŠ” 좔상 자료 ν˜•μ‹κ³Ό ν˜Όλ™ν•˜μ§€ 말기 λ°”λž€λ‹€.) ADTλŠ” ν•˜λ‚˜ μ΄μƒμ˜ 자료 μƒμ„±μžλ“€λ‘œ 이루어진 자료 ν˜•μ‹μΌ 뿐이닀. κ·ΈλŸ¬ν•œ 자료 μƒμ„±μžλ“€μ€ 각각 0개 μ΄μƒμ˜ 인수λ₯Ό 받을 수 μžˆλ‹€. μ΄λŸ¬ν•œ 자료 ν˜•μ‹μ„ ν•΄λ‹Ή 자료 μƒμ„±μžλ“€μ΄ ν•©(sum) λ˜λŠ” 합집합(union)이라고 λΆ€λ₯΄λ©°, 각각의 자료 μƒμ„±μžλŠ” ν•΄λ‹Ή μΈμˆ˜λ“€μ˜ κ³±(product)이라고 λΆ€λ₯Έλ‹€. λŒ€μˆ˜μ  자료 ν˜•μ‹μ΄λΌλŠ” 이름에 걸맞게 λŒ€μˆ˜ν•™(algebra)의 μš©μ–΄λ“€μ΄ μ“°μž„μ„ μ£Όλͺ©ν•˜κΈ° λ°”λž€λ‹€.

λŒ€μˆ˜μ  자료 ν˜•μ‹μ„ λ‹€λ₯Έ 자료ꡬ쑰의 μ •μ˜μ— μ‚¬μš©ν•  수 μžˆλ‹€. 그럼 κ°„λ‹¨ν•œ 이진 트리 자료ꡬ쑰λ₯Ό μ •μ˜ν•΄ 보자.

sealed trait Tree[+A]
case class Leaf[A](value: A) extends Tree[A]
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]

ADT와 μΊ‘μŠν™”
λŒ€μˆ˜μ  자료 ν˜•μ‹μ΄ ν˜•μ‹μ˜ λ‚΄λΆ€ ν‘œν˜„μ„ 곡용(public)으둜 λ…ΈμΆœν•˜λ―€λ‘œ μΊ‘μŠν™”λ₯Ό μœ„λ°˜ν•œλ‹€λŠ” λΆˆν‰μ΄ μžˆμ„ 수 μžˆλ‹€. ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ—μ„œλŠ” μΊ‘μŠν™” 문제λ₯Ό λ‹€λ₯΄κ²Œ μ·¨κΈ‰ν•œλ‹€. ν•¨μˆ˜μ  자료 ν˜•μ‹μ—λŠ” κ·Έ λ‚΄λΆ€λ₯Ό λ…ΈμΆœν•œλ‹€κ³  해도 λ²„κ·Έλ‘œ μ΄μ–΄μ§€κ±°λ‚˜ λΆˆλ³€μ‹μ΄ μœ„λ°˜λ λ§Œν•œ μ˜ˆλ―Όν•œ κ°€λ³€ μƒνƒœκ°€ λ³„λ‘œ μ—†λ‹€. ν˜•μ‹μ˜ 자료 μƒμ„±μžλ₯Ό λ…ΈμΆœν•΄λ„ λ³„λ¬Έμ œκ°€ μ—†λŠ” κ²½μš°κ°€ 많으며, κ·ΈλŸ¬ν•œ λ…ΈμΆœμ˜ 결정은 자료 ν˜•μ‹μ˜ API 쀑 μ–΄λ–€ 것을 곡용으둜 λ…ΈμΆœν•  것인지λ₯Ό κ²°μ •ν•˜λŠ” 것과 μƒλ‹Ήνžˆ λΉ„μŠ·ν•œ λ°©μ‹μœΌλ‘œ 이루어진닀.