Skip to content

Instantly share code, notes, and snippets.

@linearhw
Last active December 15, 2017 05:35
Show Gist options
  • Save linearhw/4b3515b00d8840b3b9364cbc8a88c2ae to your computer and use it in GitHub Desktop.
Save linearhw/4b3515b00d8840b3b9364cbc8a88c2ae to your computer and use it in GitHub Desktop.

개요

  • 자료 처리를 수학적 함수의 계산으로 취급하고
  • 상태와 가변 데이터를 멀리하며
  • 문제를 step by step 이 아닌 divide and conquer 로 해결하는 방식

예제

  • 기존 Factorial
var result = 1
for i in 1...n {
  result *= i
}
  • FP Factorial
fac n = foldr (*) 1 [1..n]
-- | f x [y1,y2..yk] = f y1 (f y2 (... (f yk x) ...))
  • 기존 Persons
var persons: [Person] = []
for name in names {
    let person = Person(name: name)
    if person.isValid {
        persons.append(person)
    }
}
  • FP Persons
let persons = names
    .map(Person.init)
    .filter { $0.isValid }

상세

  • pure function 를 조합한다
    • 같은 입력이 주어지면 항상 같은 출력을 반환한다.
    • 즉 코드 내부에 '숨겨진 입력'이나 '숨겨진 출력'이 없다.
    • 테스트할 때 편리함
  • shared state 를 피한다.
    • shared state 의 문제점: history 를 전부 알아야 한다 / 호출 순서에 따라 결과가 달라질 수 있다
  • mutable data 를 피한다.
    • const 는 불변 객체를 만들지 않는다. 바인딩이 참조하는 객체를 변경할 수는 없지만, 여전히 객체의 속성은 변경 가능하다.
const a = Object.freeze({
  foo: { greeting: "Hello"},
  bar: 'world'
});

a.foo.greeting = 'Goodbye';
console.log(`${a.foo.greeting}, ${a.bar}${a.baz}`); // Goodbye, world!
  • side effects 를 피한다.
    • 반환값 이외에 함수 밖에서 관찰할 수 있는 앱의 상태 변화. ex) 콘솔 로깅, 파일에 쓰기, 네트워크에 쓰기, side effect 가 있는 다른 함수 호출.

Swift

  • let 으로 지정한 변수의 경우 속성도 변경 불가능
  • 함수의 parameter 로 들어온 변수는 변경 불가능한 게 default
  • FP의 특징이라고 할 수 있는 Higher Order Function 이 있다 (filter, map, reduce)
    • First Class: can be assigned to values and passed in and out
    • Higher Order: can be accepted as parameters or used as return value
  • 하지만 function unit 이 아닌 type unit 의 composition 을 한다. (ex. struct, enum)
  • 그리고 type 에 context 정보가 들어간다. (ex. 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
    }
}

수정 버전

struct Token {
    let string: String
}
struct Credential {
    var username: String
    var password: String
}
enum Result<Value> {
    case success(Value)
    case failure(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
     }
}

OOP

  • OOP 는 feature 개수가 fixed 이고 class 개수는 계속 늘어날 예정일 때
  • FP 는 class 개수는 fixed 인데 feature 개수는 계속 늘어날 예정일 때

언어의 특징에 잘 맞게 쓰는 게 중요

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment