아요 개발 일기

[iOS] 함수형 프로그래밍 (Function Programming) 본문

iOS

[iOS] 함수형 프로그래밍 (Function Programming)

소진이 2023. 1. 3. 15:37

안녕하세요!

오늘은 함수형 프로그래밍에 대해서 알아보도록 하겠습니다!

Swift는 다중 패러다임 프로그래밍 언어이며, 아래와 같은 프로그래밍 패러다임을 차용하고 있습니다.

- 명령형 프로그래밍 패러다임

- 객체지향 프러그래밍 패러다임

- 함수형 프로그래밍 패러다임

- 프로토콜 프로그래밍 패러다임

아주 다양하죠? Swift가 함수형 프로그래밍 패러다임을 차용한 이유를 살펴 봅시다!

 


함수형 프로그래밍 🤔

프로그램이 상태의 변화 없이 데이터 처리를 수학적 함수 계산으로 취급하고자 하는 프로그래밍을 말합니다.

값이나 상태의 변화 보다는 함수 자체의 응용을 중요하게 여깁니다. 객체 대신 수 많은 함수들이 존재하고 함수끼리 값을 주고 받으면서 나오는 결과가 함수형 프로그래밍의 세계입니다.

 

 

  명령형 프로그래밍 함수형 프로그래밍
프로그래머의 초점 작업 수행 알고리즘
상태의 변경 추적
원하는 정보
필요한 변환
상태 변경 중요 없음
실행 순서 중요 중요도가 낮음
주요 흐름 제어 제어문(반복문, 조건문 등)
함수(메소드)호출
순환(재귀)함수 호출 등의 함수 호출로 제어
주요 조작 단위 클래스나 구조체의 인스턴스 함수

 

 

장점

  • 여러가지 연산 처리 작업이 동시에 일어나는 프로그램을 짜기 쉽다.
  • 멀티코어 혹은 여러 연산 프로세서를 사용하는 시스템에서 효율적인 프로그램을 만들기 쉽다.
  • 상태변화에 따른 부작용에서 자유로워지므로 순수하게 기능 구현에 초점을 맞춰 설계가 가능하다.

 

 


 

특징

1.  순수 함수(Pure Function)

특정 input에 대해서 동일한 output을 반환하는 함수를 말합니다.

  • 함수의 동작이 외부에 있는 변수에 영향을 받거나 주지 않아 side-effect가 발생하지 않는다.
  • 특정 입력값에 대해서 항상 동일한 결과를 낸다.

아래 코드를 외부 변수를 사용하지 않는 순수함수로 변경해보겠습니다.

var sum = 0
func solution(_ nums: [Int]) -> Int {
    for i in nums {
        sum += i
    }
    return sum
}

let numAdd = solution(nums)
print("numAdd : \(numAdd)")
//numAdd : 15

 

👉  전역 변수 sum을 함수 안으로 옯겨서 지역변수로 만들어줍니다.

func solution_PF(_ nums:[Int]) -> Int {
    var sum_ = 0
    for i in nums {
        sum_ += i
    }
    return sum_
}
let numAdd_PF = solution_PF(nums)
print("numAdd_PF : \(numAdd_PF)")
//numAddRst_PF : 15

 


2.  1급 객체

함수형 프로그래밍에서 함수를 "1급 객체"로 취급합니다.

즉, 다양한 종류의 함수를 호출, 전달, 반환하는 등의 동작만으로도 프로그램을 구현할 수 있다는 것입니다.

  • 전달인자로 전달할 수 있다.
  • 동적 프로퍼티 할당이 가능하다.
  • 변수나 데이터 구조 안에 담을 수 있다.
  • 반환 값으로 사용할 수 있다.
  • 할당할 때 사용된 이름과 관계없이 고유한 객체로 구별 가능하다.

 


 

3.  고차 함수(Higher-Order Function)

함수를 파라미터로 받거나 함수를 리턴하는 함수를 고차함수라고 합니다.

Swift에서는 Foundation 라이브러리에서 고차함수(filter, map, reduce)를 지원하고 있습니다.

 

 

< 함수를 파라미터로 전달하는 예 >

let arr = [1,2,3,4,5]
func isEven(_ i:Int) -> Bool{
    return i % 2 == 0
}
let result = arr.filter(isEven)
print("result: \(result)")
//evens: [2, 4]

let evens2 = arr.filter { i in
    i % 2 == 0
}
print("result2: \(result2)")
//result2: [2, 4]

 

 

< 함수를 리턴하는 함수 >

func multiply(_ a:Int) -> (Int) -> Int {
    
    func multi(_ b:Int) -> Int {
        return a * b
    }
    
    return multi
}

let result = multiply(10)(20)
print("result: \(result)")
//area: 200



func multiply2(_ a:Int) -> (Int) -> Int {
    return { b in a * b }
}

let n = multiply(10)
let result2 = n(20)
print("result2: \(result2)")
//result2: 200

 


 

4.  함수의 합성(Composition)

함수의 반환값이 다른 함수의 입력값으로 사용되는 것.

당연히 함수의 반환값과 이것을 입력으로 받아들이는 타입이 서로 같아야 합니다.

 

함수형 프로그래밍(FP)에서는 함수를 1급 객체로 사용하므로 당연히 함수의 합성(Composition)도 가능하다.

 

 

< 간단한 함수 합성 >

func f1(_ num: Int) -> Int {
    return num + 3
}

func f2(_ i: Int) -> String {
    return "\(i) 빼기 3은 f1의 파라미터"
}

// 함수를 변수에 할당할 수 있는 고차함수적 부분..!
let result: String = f2(f1(10))

 

 


 

5.  커링(Currying)

여러개의 파라미터를 받는 하나의 함수를 하나의 파라미터를 받는 여러개의 함수로 쪼개는 기법

 

🧐  굳이 왜 커링을 하나요?

함수의 output이 다른 함수의 input 으로 연결되면서 함수의 합성이 일어납니다.

합성이 될려면 함수의 output과 input의 타입과 개수가 같아야 하는데,

함수의 output은 하나 밖에 없으니 input도 한개라면 합성이 쉬워집니다.

즉, 함수의 합성(Composition)을 원할하게 하기위해서 커링을 사용합니다.

 

 

< 커링 전 >

func multiply(_ s1: Int, s2: Int) -> Int {
    return s1*s2
}

 

< 커링 후 >

// 이렇게 파라미터 분리!
func f1(_ s1: Int) -> Int
func f2(_ s2: Int) -> Int

func multiply(_ s1: Int) -> (Int) -> Int {
    return { s2 in
        return s1 * s2
    }
}

let result = multiply(10)(20)

 

< 커링 전 >

func filterSum(_ arr: [Int], _ n: Int) -> Int {
    return arr.filter({$0 % n == 0}).reduce(0, +)
}

 

< 커링 후 >

func filterSum2(_ n: Int) -> [Int] -> Int {
    return { arr in
        return arr.filter{ $0 % n == 0}.reduce(0, +)
    }
}

func solution(_ nums: [Int], _ r: Int) -> Int {
    let filterResult = filterSum2(r) // 이게 지금 Int가 반환되야할 <<함수>>가 할당된거임.
    return result = filterResult(nums)
}

커링.. 아직 잘 이해가 안가서 더 봐야겠어요,,,

Swift가 채택한 프로그래밍 방식들을 잘 활용하여 코드를 작성해야하는데.. 

열심히 노력해봐야겠습니다! 화이팅!!

 

참고 블로그 🙇🏻‍♀️

https://mangkyu.tistory.com/111

https://borabong.tistory.com/5

https://coding-rengar.tistory.com/13    

https://qteveryday.tistory.com/310