Skip to content

Latest commit

 

History

History
109 lines (93 loc) · 6.07 KB

pure_function.md

File metadata and controls

109 lines (93 loc) · 6.07 KB

순수함수 (Pure Function) 에 대하여

순수 함수란?

  • 어떠한 입력에 대해 항상 같은 출력을 만드는 함수를 의미한다.
  • 즉, 외부의 영향을 받거나 주지 않는 것, side-effect(부수 효과)가 없는 것을 말한다.

순수 함수의 특징

  • 동일한 입력에 대해 동일한 출력을 가진다.
  • side-effect 가 없다.
  • 두 개의 순수한 표현식 사이에 데이터 의존성이 없는 경우,
    • 순서를 반대로 하거나 병렬로 수행이 가능하다.
    • 서로 간섭을 할 수 없다.
    • 그렇기 때문에 thread-safe 하다.

순수함수가 아닌 예시

ex1) 전역(혹은 지역) 프로퍼티에 의존하는 경우

// side-effect (O)
var counter: Int = 0

func increament(num: Int) -> Int {
    counter += 1
    return counter
}
  • increament(num:) 함수는 함수 바깥에 있는 전역 프로퍼티 counter 값을 변경 시킨다.
  • 다른 함수가 counter 프로퍼티에 접근할 지도 모른다.
  • 그렇기에 이러한 로직은 프로퍼티의 값이 바뀜으로써(mutating the property) 예상치 못한 부수효과(side-effect)를 발생시킬 여지가 있으므로 순수함수가 아니다.

ex2) 랜덤 요소에 의존하는 경우

// side-effect (O)
func getRamdomNumber(maxNum: Int) -> Int {
    return Int.random(in: 0...maxNum)
}
  • 함수에 랜덤적 요소가 포함되어있다면 테스트하기 힘들다.
  • 순수함수는 나의 코드를 테스트하기 쉽게 한다.
  • getRandomNumber(maxNum:) 함수는 0부터 maxNum` 사이의 숫자를 랜덤하게 리턴해준다.
  • 위와 같이 랜덤 요소를 리턴하는 함수로 테스트(= 충분한 unit test)를 할 수 있을까?
    • 여러 input을 통해 함수의 output을 테스트해볼 수는 있을 것이다.
    • outputgetRandomNumber(maxNum:) 에 주어진 input에 의존하게 된다.
    • 그 말은, 여러 input 경우의 수에 따른 테스트를 실행함으로써 테스트가 가능하고, 그 당시 다른 테스트들을 방해하는 테스트는 없을 것이다.
    • 그래서 순수함수라고 착각할 수 있다.
  • 이 함수는 함수를 실행할 때마다 같은 결과를 낸다는 보장이 없다.

순수함수의 예시

[ 순수함수의 조건 ]
1. 항상 같은 결과를 리턴한다.
2. 전역으로 선언된 것의 상태를 변경 시키지 않고 그대로 둔다.
// side-effect (X)
func hello(name: String) -> String {
    return "안녕! \(name)아!"
}
  • hello(name:) 함수는 위의 두 조건을 만족하므로 순수함수라고 볼 수 있다.
    • 1번 조건 만족: 항상 같은 input에 같은 output을 리턴한다.
    • 2번 조건 만족: 전역 변수 즉, 전역적으로 선언된 상태값(global state)을 변경시키지 않는다.

순수함수의 장점

  • 읽기 쉽고, side-effect가 없다.

    • 그러므로 문제가 발생시 그 이유에 대해 쉽게 추론이 가능하다.
    • 명확히 정의된 함수의 파라미터를 가지고 있다. 그러므로 도출된 output은 온전히 input 파라미터에 의해 결정된다.
  • 함수는 오직 input 파라미터에 의해 결정되므로, 해당 코드는 이식이 가능하다. (= portable)

    • 이 말은, 함수는 앱 전체 어느 곳에서든 사용히 가능하다는 뜻이다.
  • 테스트 코드 작성에 용이하다.

    • 주어진 다양한 input에 대한 예측가능한 결과를 코드를 통해 유추할 수 있다면, 우리는 테스트할 수 있다.
    • 여기저기 공유되고 있는 가변상태(mutable state)는 모든 경우의 수를 빼놓지 않고 테스트 하기 어렵다.
    • 이것은 독립적이고 반복 가능한 테스트에 반하는 아이디어이다.
  • 정의상으로 순수함수는 참조 투명성(referential transparency)을 갖는다.

    • 이는 프로그램의 결과를 변경하지 않고 표현식을 값으로 대체할 수 있음을 의미한다.
(1) : f(x) = x + 1
(2) : y = f(x) + 1
(3) : y = x + 1 + 1

위의 3 가지 수식이 있다고 할 때, (2)와 (3)은 다른가? 둘은 같다.
식이 원래 가지는 의미가 변하지 않고 대체가 가능하다.
  • 메모리의 관점에서는

    • 한번 값이 할당된 메모리 위치에는 새로운 값을 다시 할당하지 않는다는 것이 참조 투명성의 필수 조건이다.
    • 이 조건이 만족된다면, 어떤 함수를 많이 호출(callback) 하더라도, 항상 동일한 결과를 얻게 된다.
    • (프로그램이 사용하는 컴퓨터 메모리의 값은 프로그램이 실행되는 동안에는 절대 변하지 않는다.)
  • 구조체, 열거형과 같은 값 타입(value type)은 우리가 상태를 변경하고자할 때 명확히 명시한다.

  • 즉, 함수가 상태를 변경하고자 할 때는 mutating 키워드를 꼭 필요로 한다는 뜻이다.

  • 이 키워드를 통해 참조 투명성을 갖을 수 있다.

    • 순수함수들은 작성하기 좋고, 테스트가 가능한 코드에 중요하다는 것을 나타내기 때문에 유용하다.
[ 참조 투명성(referential transparency) ]
- 일반적으로 응용프로그램의 동작에 영향을 미치지 않고 항상 함수를 반환값으로 대체할 수 있음을 의미한다.
- 코드의 재사용성을 보장합니다.
- 데이터가 가변상태인 것을 거부한다. (데이터의 상태 변경 불가)
- 가변이 가능하다면, 동일한 함수의 두 호출은 잠재적으로 두 개의 서로 다른 결과를 만들어낼 가능성이 있고, 텍스트와 유지보수가 어렵다.

- 표현식을 결과값으로 대체했을 때 아무 문제가 발생하지 않는다면, 해당 표현식은 "참조 투명성"을 갖는다고 한다.