[Scala] Scala 기초 - 함수형 프로그래밍 (Functional Programming)

Hyunjun Kim·2025년 4월 15일
0

Data_Engineering

목록 보기
38/153

8. 함수형 프로그래밍 (Functional Programming)

8.1 소개

함수형 프로그래밍은 순수 함수(pure functions) 와 불변값(immutable values) 를 위주로 사용해서 어플리케이션을 만드는 프로그래밍 스타일이다.
수학을 하는 것처럼 코딩을 하는 느낌이라고 생각하면 된다.

8.2 순수 함수

아래와 같은 조건을 가진 함수를 순수함수라고 한다.

  • 함수의 리턴값이 자체 입력값에만 의존
  • 어떠한 숨겨진 상태도 변경하지 않음
  • 어떠한 백도어도 없음 (데이터베이스, 인터넷, 파일 등으로부터 읽어오는 데이터가 없음)

이러한 정의에 따라 순수 함수는 어느 경우에도 같은 값을 입력하면 항상 같은 값을 출력한다.

val abs: Int = (-5).abs // 절대값 함수 (순수 함수)
val ceil: Double = (2.1).ceil // 올림 함수 (순수 함수)
val isEmpty: Boolean = "Hello world!".isEmpty // 순수 함수

println(abs)
// 출력: 5
println(ceil)
// 출력: 3
println(isEmpty)
// 출력: false

역으로 불순수 함수(impure functions)는 위 조건을 충족시키지 않는다. 예시를 살펴보자.

val nums = List(1,2,3)
val foreach = nums.foreach{println} // foreach 불순수 함수

println(foreach)
// 출력: ()

Unit "()" 이 출력되었다. 따라서 foreach 는 출력값이 없다. 이처럼 Unit 을 리턴하는 함수는 불순수 함수다.
이번에는 간단하게 순수 함수를 한 번 만들어 보자.

def square(num: Int): Int = num * num // 제곱 순수 함수
val square = square(2)
println(square)
// 출력: 4

8.3 함수의 변수화

Scala 에서는 함수를 변수로 사용할 수 있다.
이는 map 이나 filter 같은 함수를 사용하면서 코드를 더 간결하게 짤 수 있다.

예시를 보면서 이해해 보자.

val nums = List(1,2,3,4,5)
def double(i: Int): Int = i * 2 // double 함수 정의

val doubles = nums.map(double) // 함수를 변수처럼 사용
println(doubles)
// 출력: List(2,4,6,8,10)

8.4 케이스 클래스 (Case Classes)

케이스 클래스는 일반 클래스에서 기능들을 더한 클래스다. 케이스 클래스를 사용하면 아래와 같은 차이점과 장점들이 있다.

8.4.1 게터 메소드 자동생성 / 세터 메소드 없음

함수형 프로그래밍에서는 자료형을 업데이트하면 안된다. 필요할때마다 새로 객체를 생성하면서 코드를 짜야 한다.
그래서 케이스 클래스 생성자 변수는 val 필드로 만들어진다. 따라서 accessor (getField 같은) 메소드는 만들어지지만, mutator (setField 같은) 메소드는 만들어지지 않는다.

case class Car(name: String, engineType: String) // 참고) case class 에서는 "new" 키워드가 필요하지 않다.
val porsche911 = Car("Porsche 911", "3.0L")

println(porsche911.name) // 출력: "Porsche 911"
porsche911.name = "Porsche 912" // Not allowed!

8.4.2 복제 (copy) 메서드

케이스 클래스는 객체를 복제하거나 하나 또는 그 이상의 필드를 업데이트해야 할 때 유용한다.

case class Car(brand: String, model: String, firstManufacturedYear: Int)
val porsche911 = Car("Porsche", "911", 1963)
val porsche992 = porsche911.copy(model="992", firstManufacturedYear=2019)

8.4.3 Equals & hashCode

케이스 클래스는 equalshashCode 메소드가 자동으로 생성되어 두 객체를 비교할 수 있다. equals 를 사용하면 두 객체가 같은지 체크할 수 있다. hashCode 메소드는 인스턴스를 map 의 키로도 사용할 수 있게 된다.
이는 Scala 에서 이전 4장에서 배웠던 Pattern Matching 을 사용할 수 있게 되어 아주 큰 장점이 된다.

val avante = Car("Hyundai", "Avante", 1990)

println(porsche911 == avante)
// 출력: false
profile
Data Analytics Engineer 가 되

0개의 댓글