주요 함수형 프로그래밍 언어

객체지향과 함수형 프로그래밍 패러다임 비교

주요 함수형 프로그래밍 언어

Haskell

Scala

Clojure

Erlang/Elixir

OCaml

핵심 철학

OOP

객체 중심 설계

객체는 상태와 행동을 가진 독립적인 단위로

객체 지향은 현실 세계 개체/개념을 프로그램 내의 객체로 모델링하고 객체 간의 협력을 통해 문제를 해결한다

class Marine {
    
    // 마린 유닛의 상태 (체력, 공격력, 생산 비용)
    private int hp;
    private int power;
    private int cost;
    
    // 마린 유닛의 동작
    public void attack(Unit target) {
        int targetHp = target.getHp();
        target.setHp(target - this.power);
    }
}

FP

함수 중심 설계

프로그램은 입력을 받아 출력을 반환하는 순수 함수의 조합으로 구성된다

상태 변경을 최소화하며 불변성을 유지한다

객체와 달리 상태와 행동을 분리하여 문제 해결 과정을 함수로 표현한다

// 입력을 받아 출력을 반환하는 함수
def attack(targetHp:Int, attackerPower: Int): Int = targetHp - attackerPower

val marinePower = 10
val zealotHp = 5

val remainingHp = attack(zealotHp, marinePower)
println(remainingHp)

주요 개념

OOP

상속: 객체 관계 정의, 필드/메서드 재사용, 기능 확장 및 재정의

abstract class Unit {
    
    protected int hp;
    
    protected abstract void attack();
}

class Marine extends Unit {
    
    @Override
    public void attack() {
    }
}

추상화: 객체 핵심 로직/행위 표현, 불필요한 세부 구현 감춤

interface UnitFactory {
    Unit generate();
}

캡슐화: 정보 은닉, 데이터 보호

class Marine extends Unit {
    
    private int power;
    
    private void upgrade() {
        this.power++;
    }
}

다형성: 기능 확장

interface UnitFactory<Unit> {
    Unit generate();
}

class Nexus implements UnitFactory<Probe> {
    Probe generate() {
    }
}

class Hatchery implements UnitFactory<Drone> {
    Done generate() {
    }
}

자세한 내용

FP

순수 함수(Pure Function): 같은 입력에 대해 항상 같은 출력을 반환하며, 부작용을 발생시키지 않는 함수

def square(x: Int): Int = x * x

println(square(4)) // 같은 입력(4)에 대한 같은 출력(16) 

고차 함수(Higher-Order Function): 함수를 인자로 전달하거나 반환하는 함수

def applyFunction(x: Int, f: Int => Int): Int = f(x)

val result = applyFunction(5, sqaure)
println(result) // 출력: 25

불변성(Immutability): 데이터는 변경되지 않으며, 새 데이터를 생성함

val originalList = List(1, 2, 3)

val newList = originalList.map(_ * 2) // 새 리스트 생성, 원본 변경 X

println(newList)       // 출력: List(2,4,6)
println(originalList)  // 원본 리스트 출력: List(1,2,3) 

일급 객체(First-Class Citizens): 함수가 변수처럼 전달되거나 반환될 수 있음

val multiplyByTwo: Int => Int = _ * 2 // 함수를 변수에 할당
val numbers = List(1, 2, 3)
println(numbers.map(multiplyByTwo)) // 함수를 인자로 전달

상태 관리

OOP

객체 내부에 상태를 저장하며, 메서드를 통해 조작한다

프로그램의 상태 변화가 객체 간의 상호작용에 의해 발생한다

// 질럿, 마린 생산
Zealot zealot = gateway.generate();
Marine marine = barrack.generate();

// 공격 메서드를 통해 질럿의 상태 변화 발생
marine.attack(zealot);

FP

상태 변경을 피하며 불변성을 유지한다

상태를 수정하는 대신 새로운 상태를 반환한다

case class Counter(value: Int) {
  // 새로운 Conuter 클래스 반환
  def increment: Counter = Counter(value + 1)
  def decrement: Counter = Counter(value - 1)
}

val counter = Counter(0)
val newCounter = counter.increment.increment.decrement

println(counter)           // 출력: 0 (원본 변경 X)
println(newConuter.value) // 출력: 1 (새로운 상태)

코드 구조

OOP

상태와 행동을 캡슐화한 클래스를 사용한다

코드가 객체를 중심으로 구조화되는 특징을 가진다 -> 도메인 모델링에 적합

// 상태와 행동이 한 객체에 존재한다
class Hydralisk {
    
    private int hp;
    private int power;
    private int cost;
    private int speed;
    
    public void upgrade() {
        if (this.power == MAX_POWER) {
            return;
        }
        
        this.power++;
    }
}
// 히드라리스크의 upgrade 메서드를 통해 power 필드를 조작한다
Hydralisk hydralisk = new Hydralisk();
hydralisk.upgrade();

FP

데이터와 함수의 조합으로 문제를 해결한다

함수 체이닝이나 고차 함수를 통해 간결하고 읽기 쉬운 코드를 작성할 수 있다

val numbers = List(1, 2, 3, 4, 5)

val sumOfSquares = numbers
  .filter(_ % 2 == 0)
  .map(sqaure)
  .sum

println(sumOfSquares) // 출력: 20 (2^2 + 4^2)

병렬 처리

OOP

상태 변경이 빈번하므로 병렬 처리와 동기화가 어렵다

공유 상태를 관리하기 위해 락(Lock)과 같은 동기화 메커니즘이 필요함

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// Stream API 사용
int sumOfSquares = numbers.parallelStream()
                          .mapToInt(n -> n * n)
                          .sum();

System.out.println(sumOfSquares) // 출력: 385

FP

불변성과 순수 함수로 인해 병렬 처리에 유리하다

공유 상태가 없으므로 동기화 문제를 회피할 수 있다

val numbers = (1 to 10).toList

// 각 숫자를 비동기적으로 제곱한 뒤 합산
val parallelResult = numbers.par.map(sqaure).sum

println(parallelResult) // 출력: 385 (1^2 + 2^2 + ... + 10^2)

장단점

OOP

장점

단점

FP

장점

단점