학습
Scala 함수형 프로그래밍 패턴
Scala 함수형 프로그래밍 패턴 — 중급
함수형 프로그래밍 패턴
1. 도입 (왜 배워야 하는가)
함수형 프로그래밍은 코드의 가독성, 유지보수성, 재사용성을 높여줍니다. 특히 대규모 시스템을 개발할 때, 이러한 특성은 팀의 생산성과 프로젝트의 성공에 큰 영향을 미칩니다. 함수형 프로그래밍 패턴을 이해하지 못하면, 복잡한 비즈니스 로직을 구현할 때 가독성이 떨어지고, 디버깅이 어려워지며, 코드의 중복이 발생하여 유지보수 비용이 증가할 수 있습니다. 따라서 이 패턴을 배우는 것은 현대 소프트웨어 개발에서 필수적입니다.
2. 핵심 개념 설명
- 고차 함수 (Higher-Order Function): 함수를 인자로 받거나, 함수를 결과로 반환하는 함수입니다. 이는 함수의 재사용성과 유연성을 높이는데 기여합니다.
- 불변성 (Immutability): 데이터가 한 번 생성되면 변경되지 않는 특성입니다. 이는 프로그램의 예측 가능성을 높이고, 사이드 이펙트를 줄이는 데 기여합니다.
비유: 고차 함수는 요리에서의 '셰프'와 비슷합니다. 셰프가 레시피를 가지고 요리를 하는 것처럼, 고차 함수는 다른 함수를 가지고 새로운 기능을 만들어낼 수 있습니다.
비유: 불변성은 한 번 만들어진 조각상을 바꾸지 않는 것과 같습니다. 조각상이 변경되지 않기 때문에, 항상 같은 모습을 유지합니다.
| 용어 | 정의 |
|---|---|
| 고차 함수 | 함수를 인자로 받거나 반환하는 함수 |
| 불변성 | 데이터가 생성된 후 변경되지 않는 특성 |
3. 기본 코드 예제
// 고차 함수 예제
def applyFunction(f: Int => Int, value: Int): Int = f(value)
// 제곱 함수
def square(x: Int): Int = x * x
// 고차 함수 호출
val result = applyFunction(square, 5)
// result는 25가 됩니다.
실행 결과: result: 25
applyFunction 함수는 다른 함수를 인자로 받습니다.f(value)를 통해 인자로 받은 함수 f를 실행합니다.square 함수는 주어진 숫자의 제곱을 반환합니다.applyFunction(square, 5)를 호출하면 5의 제곱인 25가 반환됩니다.4. 실전 활용 예제
예제 1: 쇼핑몰에서 장바구니 총합 계산
case class Item(name: String, price: Double)
def calculateTotal(items: List[Item]): Double = {
items.map(_.price).sum
}
val cartItems = List(Item("사과", 1000), Item("바나나", 2000))
val total = calculateTotal(cartItems) // 총합: 3000
상황 설명: 쇼핑몰에서 장바구니에 담긴 상품들의 총합을 계산할 때 이 패턴을 사용하여 각 상품의 가격을 쉽게 추출하고, 합산할 수 있습니다.
예제 2: 필터링 조건에 따라 사용자 목록 가져오기
case class User(name: String, age: Int)
def filterAdults(users: List[User]): List[User] = {
users.filter(_.age >= 18)
}
val usersList = List(User("철수", 17), User("영희", 22))
val adults = filterAdults(usersList) // 성인 목록: List(User("영희", 22))
상황 설명: 사용자 목록에서 성인을 필터링할 때, 이러한 함수형 패턴을 사용하여 간결하게 조건에 맞는 사용자만 추출할 수 있습니다.
5. 흔한 실수와 주의사항
- 고차 함수 사용 시 인자 함수의 타입 오류:
- 불변성을 무시하는 코드:
- 함수형 프로그래밍 패턴은 코드의 재사용성과 유지보수성을 높인다.
- 고차 함수와 불변성은 함수형 프로그래밍의 핵심 개념이다.
- 실무에서 자주 사용하는 패턴으로 장바구니 총합 계산 및 사용자 필터링이 있다.
- 다음에 학습하면 좋은 주제: 함수형 프로그래밍의 모나드와 비동기 프로그래밍.
- 잘못된 코드:
val result = applyFunction((x: String) => x.length, 5) // 타입 불일치
- 올바른 코드:
val result = applyFunction(square, 5) // 올바른 사용
- 잘못된 코드:
var numbers = List(1, 2, 3)
numbers = numbers :+ 4 // 불변 리스트에 변경 시도
- 올바른 코드:
val numbers = List(1, 2, 3)
val newNumbers = numbers :+ 4 // 새로운 리스트 생성