Swift study - 함수형 프로그래밍

rbw·2022년 2월 14일
0

swift-study

목록 보기
4/17
post-thumbnail

FP(Functional Programming)

Swift와 함수형 프로그래밍 역사 by Rob Napier

함수형 프로그래밍이란 ?

먼저 함수형 프로그래밍은 언어나 문법이 아니라 문제에 대한 접근 방식 중 하나이다. 구조적인 방법으로 문제를 분해하고 그들을 다시 조합하는 문제 접근 방식 중 하나

예제를 살펴보면서 알아보자

var persons: [Person] = []
for name in names {
    let person = Person(name: name)
    if person.isValid {
        persons.append(person)
    }
}

Person 타입의 빈 배열을 만들고, 유효한 person인지 비교를하여 배열의 삽입을 하는 코드이다.

이것은 더 간단해 질 수 있다. 기능별로 나누어 보자면,

var possiblePersons: [Person] = []
for name in names {
  let person = Person(name: name)
  possiblePersons.append(person)
}

var persons: [Person] = []
for person in possiblePersons {
  if person.isValid {
    persons.append(person)
  }
}

이것은 두 가지 동작을 수행한다. 먼저 위에 블록에서는 Person 타입을 possiblePersons에 삽입을 한 후, 밑의 블록에서 유효성 검사를 하여 Person 배열에 삽입을 해준다. 각각의 루프에서는 이전보다 적은 양의 업무를 담당하였다.

더 간단해 질 수도 있는데, 바로 map, filter함수를 사용하는 것이다. map은 특정 리스트를 다른 리스트로 변환한다. filter는 리스트의 요소를 조건에 맞는지 확인해서 조건에 통과한 결과만을 반환해준다.

let possiblePersons = names.map(Person.init)
let persons = possiblePersons.filter { $0.isValid }

// 분리된 코드를 chaining 방식을 이용해서 합친 경우
let persons = names
    .map(Person.init)
    .filter { $0.isValid }

이러한 프로그래밍 습관을 배우고, 익숙해져야 한다. 이 방식은 persons를 어떻게 만들지에 대해 초점을 맞추는 대신 persons가 무엇인지 알려주기 때문이다.

이번에 우리가 한 방식을 순서대로 표현을 하자면,

  1. loop를 더 간단한 두개의 loop로 분해 하였다.
  2. loop안에서 일반적인(generic)형태를 발견함.
  3. 그 형태를 다시 chaining을 이용해 다시 조합하였다.

이 방식은 Haskell 프로그래머들이 시도하는 방식과 비슷하다.

함수의 결합

대부분의 함수형 프로그래밍 언어에서 compositon 기본 유닛은 함수이다. 그러나 swift의 composition 유닛은 type이다. swift 에서 결합(compose)할 수 있는 것은 class, struct, enum, protocol등이 존재한다.

// MyStruct(struct)와 Sequence(protocol)의 결합
// 이 결합으로 MyStruct는 Sequence의 모든 method를 활용 가능하다.
extension MyStruct<T>: Sequence {
    func makeIterator() -> AnyIterator<T> {
        return ... 
    }
}

단순한 조각들로부터 그들을 결합하고 조합할 수 있다.

Optional 결합

Swift에서 주로 사용되는 또 다른 composition 방법은 type에 문맥(context)를 추가하는 것이다. 가장 대표적인 것은 optional 이다. type에 추가한 문맥 정보는 다음과 같다. "이것은 존재하는 것인가?" 문맥을 추가하는 것은 다른 추가 정보를 추적하는 다른 방법보다 훨씬 강력한 방법이다.

// No value: magic value
let noValue = -1
let n = 0
if n != noValue { ... }

// No value: context
let n: Int? = 0
if let n = n { ... }

integer 가 아니다 or 값이 없다는 사실을 효율적으로 판단하는 방법은 integer optional로 변경하는 것이다

다음 예제를 살펴보자

func login(username: String, password: String,
         completion: (String?, Error?) -> Void)

login(username: "rob", password: "s3cret") {
    (token, error) in
    if let token = token {
    // success
    } else if let error = error {
    // failure
    }
}

login 함수는 특정시점에 token과 발생가능한 error를 발생시키는 예제. 좀 더 간단하게 만들어보자.

Token의 구조화

Token에 좀 더 문맥적인 의미를 부가하고 싶을 때(규칙을 가지고 있는 경우에) 이것을 좀 더 구조적(struct)으로 만들 수 있다. 그것이 우리가 struct라고 부르는 이유이다.

struct Token {
  let string: String
}

이렇게 바꾸는데에는 비용과 메모리, 참조가 요구되지 않는다. 그리고 규칙을 추가하는 것이 가능해지고, Token과 같은 type이 무엇인지도 명확하게 확인 가능하다(label, 주석 필요 x)

"AND" Type(Product)

struct Credential {
    var username: String
    var password: String
}

위 예제에서 username, password 는 함께 결합하여 보내야 하므로 그 때 필요한 typestruct이다.

구조체는 "and" type 이다

"OR" Type (Sum)

마지막으로 (Token?, Error?) 튜플을 인자로 전달하는 부분을 수정해보자. 튜플은 anonymous struct라고 할 수 있다. 따라서 튜플은 "and" type이다. 하지만 토큰과 에러는 "OR" type으로 전달해야한다.

token과 error 둘다 전달을 받은 경우라면 ?

error의 종류에 따라 처리를 어떻게 할지 결정해야할 문제인것 같다. login 하는 경우이므로, 회원가입이 안되어 있거나, 이미 다른 환경에서 접속이 되어 있다면 error도 같이 전달을 받는 경우라고 생각을 한다. 이런 경우에서는 실패로 결과값을 반환하면 될 것 같다. 아직 정확하게는 모르겠어서 좀 더 알아봐야 겠다.

여기 예제는 token 또는(or) error 를 표현하고자 한다. 이 경우에 쓰이는 type으로는 enum이 존재한다.

enum Result<Value> {
    case success(Value)
    case failure(Error)
}

단순히 value 였던 것들이 successful value, failing error가 되었다

결과적으로 다음과 같다.

func login(credential: Credential,
           completion: (Result<Token>) -> Void)
     login(credential: credential) { result in
     switch result {
     case .success(let token): // success
     case .failure(let error): // failure
     }
}

정리하며...

복잡한 것은 작고, 간단한 것으로 분리할 수 있다. - 이것이 함수형 프로그래밍의 진정한 유산이며. 우리가 swift에서 활용해야 하는 것들이다.

우리는 이렇게 간단해진 것들로부터 일반적인 해결책을 찾을수 있을 것이다. 프로그램에 대해 생각하고 판단하게 만드는 일관된 규칙을 적용하여 다시 이들을 결합 시킬 수 있다

분리한 다음, 다시 결합하세요 ! (Break it down, build it up)

profile
hi there 👋

2개의 댓글

comment-user-thumbnail
2022년 10월 18일

야무지네요

1개의 답글