루아(Lua)는 간결하면서도 강력한 스크립트 언어로, 특히 게임 개발과 임베디드 시스템에서 널리 사용됩니다.
이번 글에서는 루아의 함수와 클로저를 통해 함수형 프로그래밍의 핵심 개념을 살펴보겠습니다.
루아에서 함수는 일급 시민(first-class citizen)이며, 이를 활용한 클로저 패턴은 코드를 더욱 유연하고 표현력 있게 만들어줍니다.
루아에서 함수는 일급 시민이다
루아에서 함수는 변수에 할당할 수 있고, 다른 함수의 인자로 전달하거나 반환값으로 사용할 수 있습니다.
이는 함수형 프로그래밍의 기본 요소입니다. 루아 함수 정의 방법과 기본 사용법을 살펴보겠습니다.
-- 기본 함수 정의
function add(a, b)
return a + b
end
-- 익명 함수를 변수에 할당
local multiply = function(a, b)
return a * b
end
-- 함수를 다른 함수의 인자로 전달
function apply_operation(op, x, y)
return op(x, y)
end
print(apply_operation(add, 5, 3)) -- 8
print(apply_operation(multiply, 5, 3)) -- 15
클로저란 무엇인가?
클로저(closure)는 함수와 그 함수가 선언된 렉시컬 환경의 조합입니다.
루아에서 내부 함수는 외부 함수의 지역 변수에 접근할 수 있으며, 외부 함수가 종료된 후에도 해당 변수들을 기억합니다.
이러한 특성을 활용한 루아 클로저 예제를 살펴보겠습니다.
function create_counter()
local count = 0
return function()
count = count + 1
return count
end
end
local counter1 = create_counter()
local counter2 = create_counter()
print(counter1()) -- 1
print(counter1()) -- 2
print(counter2()) -- 1 -- 독립적인 클로저
print(counter1()) -- 3
고차 함수와 커링
고차 함수(higher-order function)는 함수를 인자로 받거나 함수를 반환하는 함수입니다.
루아에서 고차 함수를 활용한 함수 합성과 커링(currying) 패턴을 구현해보겠습니다.
-- 고차 함수 예제: map 함수 구현
function map(array, transform)
local result = {}
for i, v in ipairs(array) do
result[i] = transform(v)
end
return result
end
local numbers = {1, 2, 3, 4, 5}
local squared = map(numbers, function(x) return x * x end)
-- squared = {1, 4, 9, 16, 25}
-- 커링 예제
function curry(f)
return function(a)
return function(b)
return f(a, b)
end
end
end
local curriedAdd = curry(add)
local addFive = curriedAdd(5)
print(addFive(3)) -- 8
메모이제이션과 성능 최적화
클로저를 활용한 메모이제이션(memoization)은 함수형 프로그래밍에서 중요한 최적화 기법입니다.
루아에서 피보나치 수열 계산을 메모이제이션으로 최적화하는 예제를 살펴보겠습니다.
function memoize(f)
local cache = {}
return function(x)
if cache[x] == nil then
cache[x] = f(x)
end
return cache[x]
end
end
-- 메모이제이션이 적용된 피보나치 함수
local fib
fib = memoize(function(n)
if n <= 1 then return n end
return fib(n-1) + fib(n-2)
end)
print(fib(40)) -- 빠른 계산
실용적인 클로저 패턴들
루아 클로저를 활용한 실용적인 디자인 패턴들을 살펴보겠습니다.
팩토리 패턴, 이벤트 핸들러, 프라이빗 변수 구현 등 실제 프로젝트에서 활용할 수 있는 예제들입니다.
-- 팩토리 패턴을 활용한 객체 생성
function create_bank_account(initial_balance)
local balance = initial_balance or 0
local account = {}
function account:deposit(amount)
balance = balance + amount
return balance
end
function account:withdraw(amount)
if amount <= balance then
balance = balance - amount
return balance
else
return nil, "잔액이 부족합니다"
end
end
function account:get_balance()
return balance
end
return account
end
local myAccount = create_bank_account(1000)
myAccount:deposit(500)
print(myAccount:get_balance()) -- 1500
filter, reduce와 함수 합성
함수형 프로그래밍의 핵심 연산자인 filter와 reduce를 루아로 구현하고,
함수 합성을 통해 복잡한 데이터 처리를 간결하게 표현하는 방법을 알아보겠습니다.
-- filter 함수 구현
function filter(array, predicate)
local result = {}
for _, v in ipairs(array) do
if predicate(v) then
table.insert(result, v)
end
end
return result
end
-- reduce 함수 구현
function reduce(array, reducer, initial)
local accumulator = initial
for _, v in ipairs(array) do
accumulator = reducer(accumulator, v)
end
return accumulator
end
-- 함수 합성
function compose(f, g)
return function(x)
return f(g(x))
end
end
-- 사용 예제
local numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
local evens = filter(numbers, function(n) return n % 2 == 0 end)
local sum = reduce(evens, function(acc, n) return acc + n end, 0)
print(sum) -- 30
루아 클로저의 실제 활용 사례
게임 개발과 웹 개발에서 루아 클로저가 어떻게 활용되는지 실제 사례를 통해 알아보겠습니다.
이벤트 시스템, 상태 관리, 애니메이션 등에서 클로저의 강력함을 확인할 수 있습니다.
-- 이벤트 시스템 구현
function create_event_emitter()
local listeners = {}
local emitter = {}
function emitter:on(event, callback)
if not listeners[event] then
listeners[event] = {}
end
table.insert(listeners[event], callback)
end
function emitter:emit(event, ...)
if listeners[event] then
for _, callback in ipairs(listeners[event]) do
callback(...)
end
end
end
return emitter
end
-- 사용 예제
local emitter = create_event_emitter()
emitter:on("user_login", function(username)
print(username .. "님이 로그인했습니다")
end)
emitter:emit("user_login", "홍길동")
마치며
루아의 함수와 클로저는 함수형 프로그래밍의 강력한 도구입니다.
클로저를 통해 상태를 안전하게 캡슐화하고, 고차 함수로 코드를 더욱 추상화할 수 있습니다.
메모이제이션, 커링, 함수 합성 등의 기법을 활용하면 더욱 효율적이고 표현력 있는 코드를 작성할 수 있습니다.
함수형 프로그래밍 패러다임을 루아에 적용하면 코드의 재사용성과 유지보수성이 크게 향상됩니다.
특히 게임 개발에서 이벤트 처리, 상태 관리, 애니메이션 등을 구현할 때 클로저 패턴은 매우 유용합니다.
루아를 사용하는 개발자라면 함수와 클로저의 개념을 깊이 이해하고 활용하여 더 나은 코드를 작성할 수 있을 것입니다.
'프로그래밍 언어 실전 가이드' 카테고리의 다른 글
루아 테이블 완전 정복 – 연관 배열부터 메타테이블까지 (1) | 2025.05.16 |
---|---|
루아(Lua) 프로그래밍 언어 문법 기초: 초보자를 위한 완벽 가이드 (0) | 2025.05.15 |