iOS/Common

[Swift] 함수형 프로그래밍(feat. 순수 함수)

TDCIAN 2023. 4. 10. 20:16

 

 

Q. 함수형 프로그래밍의 정의를 설명해 줘

 

A. 함수형 프로그래밍은 계산을 수학적 함수의 조합으로 생각하고, 이러한 함수들의 조합으로 프로그램을 작성하는 프로그래밍 패러다임입니다. 이를 통해 부작용을 최소화하고, 상태 변화를 제어하여 프로그램의 안정성과 가독성을 높일 수 있습니다.

 

함수형 프로그래밍에서는 함수가 순수 함수여야 합니다.

즉, 함수는 입력값에 대해 항상 동일한 결과값을 반환하며, 함수 외부의 상태를 변경하지 않아야 합니다.

이를 통해 함수 호출이 항상 예측 가능하게 되고, 코드를 이해하고 디버깅하기 쉬워집니다.

 

또한 함수형 프로그래밍에서는 불변성을 중요시합니다.

즉, 한번 정의된 값은 변경되지 않아야 합니다.

이를 통해 병렬 처리를 용이하게 만들 수 있으며, 불필요한 상태 변경으로 인한 버그를 방지할 수 있습니다.

 

함수형 프로그래밍에서는 함수를 값으로 다루는 것이 일반적입니다.

이러한 함수는 다른 함수의 인자로 전달되거나, 함수의 반환값으로 사용될 수 있습니다.

이를 통해 코드의 재사용성추상화 수준을 높일 수 있습니다.

 

최근 함수형 프로그래밍 언어인 Haskell, Scala, Clojure 등이 등장하며, 함수형 프로그래밍은 점점 더 중요한 프로그래밍 패러다임으로 자리 잡고 있습니다.

 

 

+ Q. 함수형 프로그래밍에서 제어하고자 하는 상태 변화라는 게 무엇인지 Swift 코드로 설명해 줘

 

A. 함수형 프로그래밍에서 제어하고자 하는 상태 변화란, 프로그램이 실행되는 동안 변경될 수 있는 변수나 상태를 의미합니다.

이러한 상태 변화는 함수형 프로그래밍에서 원하는 대부분의 성질을 만족하지 않으므로, 제어하고자 하는 대상입니다.

 

예를 들어, 다음과 같이 전역 변수 'count'를 사용하여 호출 횟수를 저장하는 함수가 있다고 가정해 보겠습니다.

var count = 0

func increment() -> Int {
    count += 1
    return count
}

위 함수 'increment'는 호출될 때마다 전역 변수 'count'를 1씩 증가시키고, 그 값을 반환합니다.

이 함수는 외부 상태인 'count'를 변경하므로 순수 함수가 아닙니다.

 

함수형 프로그래밍에서는 위와 같은 외부 상태를 변경하는 코드를 피해야 합니다.

이를 해결하기 위해, 위의 함수를 상태 변화를 없앤 순수 함수로 바꿔보겠습니다.

func increment(count: Int) -> Int {
    return count + 1
}

위의 함수 'increment'는 외부 상태를 변경하지 않으며, 입력값 'count'에 1을 더한 결과를 반환합니다.

이 함수는 순수 함수이므로, 동일한 입력값에 대해 항상 동일한 결과를 반환합니다. 

함수형 프로그래밍에서는 이러한 순수 함수를 조합하여 프로그램을 구성하므로, 상태 변화를 없애는 것이 중요합니다.

 

 

+ Q. 순수 함수의 정의와 사용법에 대해 Swift 코드와 함께 설명해 줘

 

A. Swift에서 순수 함수(Pure Function)는 입력값이 같으면 항상 같은 결과값을 반환하고,

부작용(Side Effect)이 없는 함수를 의미합니다.

부작용이란 함수 외부의 어떤 상태를 변경하거나 함수 외부와 상호작용을 하는 것을 의미합니다.

 

순수 함수를 작성할 때에는 입력값과 출력값만으로 모든 것을 처리해야 하므로, 함수 내부에서 외부의 상태를 변경하지 않아야 합니다.

이는 함수의 결과가 예측 가능하고 디버깅하기 쉽게 만들어 줍니다.

 

아래는 간단한 예시 코드입니다.

// 순수 함수 예시
func addTwoNumbers(_ num1: Int, _ num2: Int) -> Int {
    return num1 + num2
}

// 순수 함수를 호출하는 예시
let result = addTwoNumbers(2, 3)
print(result) // 출력 결과: 5

위의 코드에서 'addTwoNumbers' 함수는 입력값 'num1'과 'num2'를 더한 결과를 반환하고, 함수 외부의 상태를 변경하지 않습니다.

이 함수는 순수 함수의 조건을 모두 만족하므로 예측 가능하고 디버깅하기 쉽게 작성되었습니다.

 

순수 함수는 부작용이 없기 때문에 테스트하기가 매우 쉽습니다.

입력값과 출력값만으로 테스트할 수 있으며, 외부 상태나 다른 함수와의 상호작용에 대한 고려가 필요하지 않습니다.

이는 코드의 안정성과 유지 보수성을 높여주는 장점이 있습니다.

 

 

+ Q. Swift에서 함수형 프로그래밍과 순수 함수의 관계에 대해 설명해 줘

 

A. Swift는 함수형 프로그래밍 패러다임을 지원하는 언어로, 함수를 중심으로 프로그래밍을 하는 것이 가능합니다.

함수형 프로그래밍에서는 순수 함수를 중요한 개념으로 다룹니다.

이는 함수형 프로그래밍에서 부작용을 최소화하고, 불변성을 유지하는 데 도움이 되기 때문입니다.

 

순수 함수는 입력값과 출력값만으로 모든 것을 처리하므로, 함수 호출 사이드 이펙트 없이 결과를 예측할 수 있습니다.

이로 인해 코드가 간결하고 예측 가능한 동작을 보장할 수 있어, 코드 유지보수성이 높아집니다.

또한, 순수 함수는 동일한 입력값에 대해서는 항상 동일한 출력값을 반환하므로, 병렬 처리 및 최적화를 쉽게 할 수 있습니다.

 

Swift에서도 순수 함수를 작성하는 것이 가능하며, 함수형 프로그래밍 패러다임을 따르는 코드를 작성할 수 있습니다.

예를 들어, 'map', 'filter', 'reduce'와 같은 고차 함수를 사용하면, 함수형 프로그래밍의 기본적인 개념을 쉽게 적용할 수 있습니다.

이러한 함수들은 입력값과 출력값을 변환하는 역할을 하며, 이 과정에서 부작용을 최소화하는 것이 목적입니다.

 

아래는 Swift에서 'map' 함수를 사용하는 예시 코드입니다.

let numbers = [1, 2, 3, 4, 5]
let doubledNumbers = numbers.map { $0 * 2 }
print(doubledNumbers) // 출력 결과: [2, 4, 6, 8, 10]

위의 코드에서 'map' 함수는 'numbers' 배열의 모든 요소에 대해 입력값을 2배로 만든 새로운 배열 'doubledNumbers'을 생성합니다.

이때 'map' 함수는 순수 함수의 특징을 가지며, 외부 상태를 변경하지 않고 입력값과 출력값만을 처리합니다.

이로 인해 코드가 간결하고 예측 가능한 동작을 보장할 수 있습니다.

 

+ Q. 순수 함수의 조건을 설명해 줘

 

A. 순수 함수는 아래와 같은 조건을 만족해야 합니다.

 

1. 입력값에 따라 항상 같은 결과를 반환한다.

- 동일한 입력값에 대해 항상 동일한 출력값을 반환한다.

- 외부 상태를 변경하지 않고, 오직 입력값만으로 동작한다.

 

2. 함수 외부의 상태를 변경하지 않는다.

- 함수 내부에서 외부 상태를 변경하는 부작용(Side Effect)이 없다.

- 즉, 함수가 호출된 이후 외부 상태는 변하지 않는다.

 

3. 참조 투명성(Referential Transparency)을 가진다.

- 함수의 반환값을 해당 함수의 호출문에 대치해도 프로그램의 동작에 영향을 주지 않는다.

- 즉, 함수를 호출하는 코드에서는 함수 호출 결과를 일관되게 사용할 수 있다.

 

순수 함수는 입력값과 출력값만으로 모든 것을 처리해야 하므로,

함수 내부에서 외부 상태를 변경하지 않아야 합니다.

이는 함수의 결과가 예측 가능하고 디버깅하기 쉽게 만들어 주며,

함수를 병렬 처리하거나 최적화하는 것이 쉬워집니다.

 

또한, 참조 투명성을 가지는 함수는 함수의 결과가 해당 함수의 호출문에 대치될 수 있으므로,

프로그램 전체를 이해하고 분석하는 데 도움이 됩니다.

이는 코드의 안정성과 유지 보수성을 높여주는 장점이 있습니다.

 

+ Q. 위 내용 중 함수 외부의 상태를 변경하지 않는다는 내용에 대해서 Swift 코드와 함께 설명해 줘

 

A. Swift에서 함수 외부의 상태를 변경하지 않는 예시 코드를 작성해 보겠습니다.

var count = 0 // 외부 상태

func pureFunction(x: Int, y: Int) -> Int { // 순수 함수
    return x + y
}

let result = pureFunction(x: 3, y: 5) // 순수 함수 호출

print(result) // 출력 결과: 8
print(count) // 출력 결과: 0

위 코드에서 'count' 변수는 함수 외부에서 정의되었으며, 'pureFunction' 함수 내부에서는 참조하지 않았습니다.

따라서 'pureFunction' 함수는 외부 상태를 변경하지 않으므로, 순수 함수의 조건을 만족합니다.

 

'pureFunction' 함수는 입력값 'x'와 'y'를 더한 값을 반환하는 간단한 예제입니다.

이 함수는 입력값만으로 결과를 계산하므로, 동일한 입력값에 대해서 항상 같은 출력값을 반환합니다.

또한, 함수 내부에서 외부 상태를 변경하는 부작용이 없으므로, 이 함수는 순수 함수의 조건을 모두 만족합니다.

 

위 코드에서 'pureFunction' 함수가 외부 상태를 변경하지 않으므로,

'pureFunction' 함수를 호출하더라도 'count' 변수의 값은 변하지 않습니다.

이는 순수 함수의 조건 중 하나인 "함수 외부의 상태를 변경하지 않는다"는 조건을 만족하고 있음을 보여줍니다.

 

 

+ Q. 순수 함수가 참조 투명성을 가진다는 것의 의미를 Swift 코드와 함께 설명해 줘

 

A. 순수 함수는 입력 값에만 의존하고 외부의 상태를 변경하지 않으므로, 동일한 입력값에 대해 항상 동일한 결과를 반환합니다.

이러한 특성으로 인해 순수 함수는 참조 투명성(referential transparency)을 가집니다.

 

참조 투명성이란, 함수 호출을 해당 함수의 반환 값으로 대체할 수 있는 것을 의미합니다.

예를 들어, 다음과 같은 순수 함수가 있다고 가정해 보겠습니다.

func double(_ x: Int) -> Int {
    return x * 2
}

이 함수는 입력값에 대해 항상 동일한 결과를 반환하므로, 다음과 같은 코드에서 'double(2)'는 '4'로 대체할 수 있습니다.

let y = double(2)
let z = double(2)

따라서, 위 코드는 다음과 같이 대체될 수 있습니다.

let y = 4
let z = 4

이렇게 함수 호출을 해당 함수의 반환 값으로 대체할 수 있으므로, 참조 투명성을 가진 함수는 함수형 프로그래밍에서 중요한 역할을 합니다.

함수 호출을 대체하여 프로그램을 최적화하거나, 동일한 결과를 보장하는 등의 이점을 얻을 수 있습니다.

 

 

 

 

Q. 함수형 프로그래밍의 장단점을 Swift 코드와 함께 설명해 줘

 

A. 함수형 프로그래밍의 장단점을 Swift 코드와 함께 설명해 보겠습니다. (이렇게 말해놓고 Swift 코드 안 보여줌...ㅜㅜ)

 

장점

 

1. 결합도는 낮아지고 응집도는 높아진다.

- 함수형 프로그래밍에서는 함수를 작은 단위로 분해하고, 이러한 작은 함수들을 조합하여 복잡한 동작을 수행하는 것이 일반적입니다.

- 이러한 방식으로 코드를 작성하면, 함수들 간의 결합도가 낮아지고 응집도가 높아지므로, 코드의 유지보수성과 재사용성이 높아집니다.

 

2. 부작용(Side Effect)이 없으므로 예측 가능하다.

- 함수형 프로그래밍에서는 부작용을 최소화하고, 가능하면 완전히 없애는 것이 일반적입니다.

- 부작용이 없는 함수는 입력값에만 의존하므로, 동일한 입력값에 대해서는 항상 동일한 결과를 반환하게 됩니다. 이는 코드의 예측 가능성을 높여주고, 디버깅을 용이하게 만들어 줍니다.

 

3. 병렬 처리가 쉽다.

- 함수형 프로그래밍에서는 함수 노출의 결과가 상태에 의존하지 않으므로, 동시에 여러 개의 함수를 실행하는 것이 가능합니다.

- 이러한 특성은 멀티 코어 시스템에서 병렬 처리를 수행하는 데 유용합니다.

 

4. 코드의 안정성이 높아진다.

- 함수형 프로그래밍에서는 참조 투명성을 보장하기 위해 부작용을 최소화하고, 가능하면 완전히 없애는 것이 일반적입니다.

- 참조 투명성을 보장하면, 함수의 결과가 해당 함수의 호출문에 대치될 수 있으므로, 프로그램 전체를 이해하고 분석하는 데 도움이 됩니다. 이는 코드의 안정성과 유지 보수성을 높여주는 장점이 있습니다.

 

 

단점

 

1. 학습 곡선이 높다.

- 객체 지향 프로그래밍과는 다른 개념과 방법론이 사용되기 때문에, 처음에는 학습 곡선이 높을 수 있습니다.

- 함수형 프로그래밍은 부작용이 없는 함수들로 이루어지므로, 이러한 함수들을 작성하고 이해하는 데 시간이 걸릴 수 있습니다.

 

2. 성능이 저하될 수 있다.

- 함수형 프로그래밍에서는 재귀함수나 람다식을 자주 사용합니다. 이러한 함수들은 메모리 사용량이 많아질 수 있고, 실행 시간도 길어질 수 있습니다. 따라서 성능이 중요한 경우에는 함수형 프로그래밍보다 다른 방식이 더 적합할 수 있습니다.

 

위와 같은 장단점을 고려하여, 함수형 프로그래밍을 사용할지 여부를 결정할 수 있습니다.

함수형 프로그래밍은 특정 상황에서 매우 유용할 수 있지만, 모든 상황에서 최적의 선택은 아닐 수 있습니다.

 

 

 

Q. 함수형 프로그래밍은 기존의 프로그래밍 방식의 어떤 문제를 해결할 수 있니?

 

A. 함수형 프로그래밍은 기존의 명령형 프로그래밍 방식에서 발생할 수 있는 몇 가지 문제를 해결할 수 있습니다.

 

1. 상태 변화에 대한 복잡성 감소

- 명령형 프로그래밍에서는 프로그램이 실행되는 동안 상태가 계속 변화합니다.

- 이러한 상태 변화는 프로그래밍의 복잡성을 증가시키고, 디버깅을 어렵게 만들 수 있습니다.

- 함수형 프로그래밍에서는 상태 변화를 최소화하거나 완전히 없애는 것이 일반적입니다. 이러한 방식으로 프로그래밍을 하면 프로그램의 복잡성이 감소하고, 디버깅도 더 쉬워집니다.

 

2. 부작용의 최소화

- 명령형 프로그래밍에서는 함수가 결과값 뿐 아니라 외부 상태에도 영향을 미칠 수 있습니다.

- 이러한 부작용은 코드를 예측할 수 없게 만들고, 버그를 발생시키기도 합니다.

- 함수형 프로그래밍에서는 함수가 결과값 이외의 다른 부작용을 최소화하거나 완전히 없애는 것이 목표입니다.

 

3. 병렬 프로그래밍의 용이성

- 함수형 프로그래밍에서는 상태 변화와 부작용을 최소화하므로, 병렬 프로그래밍에 용이합니다.

- 여러 개의 스레드에서 함수를 실행하더라도 결과가 같다는 것이 보장됩니다.

- 이는 동시성 문제를 해결하는 데 매우 유용합니다.

 

따라서 함수형 프로그래밍은 복잡한 시스템에서 발생하는 문제를 해결하기 위한 유용한 도구로 사용될 수 있습니다.

 

 

 

 

 

 

 

출처: ChatGPT (https://chat.openai.com/chat)