IMCAT.DEV
로그인 가입
Zig 중급 함수형

Zig 함수형 프로그래밍 패턴

Zig 함수형 프로그래밍 패턴 — 중급

Zig의 함수형 프로그래밍 패턴

1. 도입 (왜 배워야 하는가)

함수형 프로그래밍은 코드를 더 간결하고, 이해하기 쉽게 만들어 주며, 유지보수를 용이하게 해줍니다. 특히 Zig와 같은 저수준 언어에서 함수형 프로그래밍 패턴을 활용하면 메모리 관리와 성능 최적화를 손쉽게 할 수 있습니다. 함수형 프로그래밍을 모른다면 코드의 재사용성이 떨어지고, 복잡한 로직을 관리하기 힘들어질 수 있습니다. 결과적으로 버그가 생길 확률이 높아지고, 코드의 가독성이 낮아집니다.

2. 핵심 개념 설명

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

고차 함수는 함수를 인자로 받거나, 함수를 반환하는 함수를 의미합니다. 실생활 비유로는 "요리사"를 생각해 볼 수 있습니다. 요리사는 다양한 재료(함수)를 사용해 음식을 만들 수 있으며, 특정 요리법(함수)으로 음식을 조리합니다.

용어설명
고차 함수함수를 인자로 받거나 반환하는 함수
콜백 함수고차 함수에 의해 호출되는 함수

2.2. 불변성 (Immutability)

불변성은 한 번 생성된 데이터가 변경되지 않는 특성을 의미합니다. 마치 "한 번 정한 약속은 지켜야 한다"는 원칙과 비슷합니다. 데이터가 변경되지 않으면 예측 가능성이 높아지고, 코드의 안정성이 증가합니다.

3. 기본 코드 예제

다음은 Zig에서 고차 함수를 정의하고 사용하는 예제입니다.

fn applyFunction(fn: fn(i32) i32, value: i32) i32 {
    return fn(value);
}

fn double(x: i32) i32 {
    return x * 2;
}

pub fn main() void {
    const result = applyFunction(double, 5);
    std.debug.print("결과: {}\n", .{result});
}

실행 결과

결과: 10

코드 한 줄씩 동작 설명

  1. applyFunction 함수는 함수를 인자로 받습니다. 이 함수는 내부에서 인자로 받은 함수를 호출하여 결과를 반환합니다.
  2. double 함수는 입력값을 두 배로 만드는 함수입니다.
  3. main 함수에서 applyFunction을 호출하면서 double과 5를 인자로 전달합니다.
  4. applyFunction은 double(5)를 호출하고, 결과인 10을 반환하여 출력합니다.
  5. 4. 실전 활용 예제

    4.1. 쇼핑몰에서 장바구니를 구현할 때

    장바구니에 담긴 상품의 가격을 합산하는 함수를 고차 함수로 구현할 수 있습니다.

    const std = @import("std");
    
    fn sumPrices(prices: []const i32) i32 {
        var totalPrice: i32 = 0;
        for (prices) |price| {
            totalPrice += price;
        }
        return totalPrice;
    }
    
    pub fn main() void {
        const itemsPrices = [_]i32{10000, 3500, 1500};
        const total = sumPrices(itemsPrices);
        std.debug.print("총 가격: {}\n", .{total});
    }

    실행 결과

    총 가격: 15000

    4.2. 데이터 필터링

    데이터 목록에서 특정 조건을 만족하는 항목만 필터링하는 고차 함수를 사용할 수 있습니다.

    fn filter(data: []const i32, predicate: fn(i32) bool) []i32 {
        var filtered: []i32 = &[_]i32{};
        for (data) |item| {
            if (predicate(item)) {
                filtered = filtered ++ [_]{item};
            }
        }
        return filtered;
    }
    
    fn isEven(num: i32) bool {
        return num % 2 == 0;
    }
    
    pub fn main() void {
        const numbers = [_]i32{1, 2, 3, 4, 5, 6};
        const evens = filter(numbers, isEven);
        std.debug.print("짝수: {}\n", .{evens});
    }

    실행 결과

    짝수: [2, 4, 6]

    5. 흔한 실수와 주의사항

    5.1. 잘못된 함수 시그니처

    // 잘못된 예제
    fn applyFunction(fn: fn(i32) f32, value: i32) i32 { / ... / }
    • 문제: 함수의 반환 타입이 일치하지 않음.
    • 해결: 반환 타입을 일치시킴.
    • 5.2. 불변성을 무시하기

      var items = [_]i32{1, 2, 3};
      items[0] = 5; // 불변성을 위반
    • 문제: 데이터의 불변성을 위반함.
    • 해결: 새로운 배열을 생성하여 데이터를 수정.
    • 6. 정리

    • 고차 함수는 코드의 재사용성을 높여줍니다.
    • 불변성을 유지하면 코드의 안정성이 증가합니다.
    • Zig에서의 함수형 프로그래밍은 성능 최적화에 유리합니다.

다음에 학습하면 좋은 주제는 Zig의 메모리 관리와 병렬 프로그래밍입니다. 이 두 주제는 Zig의 강력한 기능을 더욱 활용할 수 있게 해줍니다.