함수형 프로그래밍(Functional Programming, FP)?

sun·2024년 1월 20일
0

함수형 프로그래밍?

👉 정의와 목적

프로그래밍 패러다임의 하나로 계산을 수학적 함수의 평가로 취급.
상태 변경 및 변경 가능 데이터를 피하는 것을 중심으로 함.
주로 side effects를 최소화하거나 제거함으로써 프로그램의 행동을 더 예측 가능하게 만드는 데 초점을 둠.
복잡한 시스템에서의 버그를 줄이고 유지보수를 용이하게 하며 테스트와 디버깅을 간소화 함.
특히 병렬 처리, 대규모 시스템, 복잡한 수학 계산 등에 적합.

❔ 프로그래밍 패러다임 :
프로그래머가 코드를 작성하고 프로그램을 구조화 하는 데 도움이 되는 기본적인 스타일 또는 철학.
프로그램을 작성하고 이해하는 방식에 영향을 미치며 특정 문제를 해결하는 데 적합한 방법론을 제시.
1) 명령형 프로그래밍 (Imperative Programming)
명령어의 순차적 실행을 통해 프로그램의 상태를 변경하는 방식을 따름. C, C++, Java
2) 선언형 프로그래밍 (Declarative Programming)
무엇을 할 것인지 명시하며 어떻게 수행할 것인지는 시스템에 맡김. SQL, HTML
2-1) 함수형 프로그래밍 (Functional Programming)
계산을 수학적 함수의 평가로 간주하고 상태 변경과 변경 가능 데이터를 피함. JavaScript, Python
2-2) 논리 프로그래밍 (Logic Programming)
논리적 명제를 사용하여 문제를 해결. Prolog
3) 객체지향 프로그래밍 (Object-Oriented Programming, OOP)
데이터를 객체로 취급하며 데이터 필드와 그 데이터와 관련된 메서드를 결합. Java, Python, C++
4) 절차적 프로그래밍 (Procedual Programming)
프로그램을 일련의 절차 또는 함수의 집합으로 구성.
명령형 프로그래밍의 한 형태. C
5) 이벤트 주도 프로그래밍 (Event-Driven Programming)
프로그램 흐름이 외부 이벤트(ex. 사용자 액션, 센서 출력)에 의해 결정되는 패러다임.
대부분의 현대적 사용자 인터페이스 프로그래밍이 이 패러다임을 따름.
사이드 이펙트 (Side Effects)
표현식이 외부의 상태를 변경하거나 함수/표현식의 평가 중 외부와 상호작용을 수행하는 것을 의미.
1) 글로벌 변수 수정 : 함수가 전역 변수나 정적 변수를 변경하는 경우.
2) 입출력 작업 : 파일이나 데이터베이스에 쓰기, 화면에 무언가를 출력하는 등의 작업.
3) 네트워크 호출 : 네트워크를 통해 데이터를 보내거나 받는 행위.
4) 하드웨어 조작 : 컴퓨터의 하드웨어 상태를 변경하는 작업.
5) 다른 함수의 호출 : 다른 사이드 이펙트가 있는 함수를 호출하는 경우.

👉 주요 특징

1. 순수 함수 (Pure Functions)

함수의 출력이 오직 입력에만 의존하며 외부 상태에 영향을 주거나 받지 않는 함수.
동일한 입력에 대해 항상 동일한 출력을 제공하며 side effects가 없음.

2. 불변성 (Immutability)

데이터가 한 번 생성되면 그 이후로 변경되지 않음.
함수형 프로그래밍에서는 데이터를 변경하는 대신 변경된 새 데이터의 복사본을 생성.
ex) java - final 사용, javascript - const 사용, python - 튜플 사용

3. 함수의 일급 객체 (First-Class Functions)

함수를 일급 객체로 취급하여 다른 객체처럼 변수에 할당하거나 다른 함수의 인자로 전달하거나 함수에서 함수를 반환 가능.
<python 코드 예시>

def greet(name):
    return f"Hello, {name}!"

# 함수를 변수에 할당
say_hello = greet

# 변수를 통해 함수 호출
print(say_hello("Alice"))  # 출력: Hello, Alice!

<java 코드 예시>

import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        // 함수형 인터페이스를 사용하여 함수를 변수에 할당
        Function<Integer, Integer> square = x -> x * x;

        // 함수 호출
        int result = square.apply(5);
        System.out.println(result);  // 출력: 25
    }
}

4. 고차 함수 (Higher-Order Functions)

함수를 인자로 받거나 함수를 결과로 반환하는 함수.
코드의 재사용성과 모듈성을 높이는데 도움.
<python 코드 예시>

def add(x, y):
    return x + y

def apply(func, x, y):
    return func(x, y)

# 고차 함수 'apply'에 'add' 함수와 인자들을 전달
result = apply(add, 5, 3)
print(result)  # 출력: 8

<java 코드 예시>

import java.util.function.Function;

public class Main {
    // 고차 함수: 함수를 인자로 받고, 함수를 반환
    public static Function<Integer, Integer> createMultiplier(int factor) {
        return x -> x * factor;
    }

    public static void main(String[] args) {
        // 고차 함수 사용
        Function<Integer, Integer> timesTwo = createMultiplier(2);
        Function<Integer, Integer> timesThree = createMultiplier(3);

        System.out.println(timesTwo.apply(5));  // 출력: 10
        System.out.println(timesThree.apply(5));  // 출력: 15
    }
}

5. 레이지 평가 (Lazy Evaluation)

표현식의 결과가 필요할 때까지 평가를 늦추는 것.
프로그램의 효율성을 높이고 무한 데이터 구조를 다룰 수 있음.
<python 코드 예시>

# Python의 제너레이터(generator)는 이 개념을 활용.
# 제너레이터는 데이터의 모든 요소를 한 번에 메모리에 로드하지 않고, 요청 시점에 하나씩 요소를 생성하여 반환

# 무한 수열 생성기
def count_up():
    n = 1
    while True:
        yield n
        n += 1

# 레이지 평가를 활용하는 제너레이터
counter = count_up()

# 첫 5개의 숫자만 생성
for _ in range(5):
    print(next(counter))
# 출력:
# 1
# 2
# 3
# 4
# 5

<java 코드 예시>

import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        // 레이지 평가를 사용하는 스트림 생성
        Stream<Integer> infiniteStream = Stream.iterate(0, x -> x + 1);

        // 스트림에서 특정 조건을 만족하는 첫 번째 요소 찾기 (처리는 여기서 수행됨)
        int firstEvenGreaterThan100 = infiniteStream
                                          .filter(x -> x > 100 && x % 2 == 0)
                                          .findFirst()
                                          .orElseThrow();
        System.out.println(firstEvenGreaterThan100);  // 출력: 102
    }
}

6. 재귀 (Recursion)

반복문보다 재귀를 사용함. 재귀는 자기 자신을 호출하는 것을 의미.

profile
Please, Steadily

0개의 댓글