// // Currying.swift // // Created by Joshua on 2020/01/12. // Copyright © 2020 Joshua. All rights reserved. // import Foundation precedencegroup Currying { // 왼쪽에서 오른쪽 방향으로 적용 associativity: left } infix operator |>: Currying // Currying 연산자 infix operator |>>: Currying // 함수 실행 연산자 infix operator <|: Currying // 클로저 획득 연산자 // MARK:- Function Object // 인자가 없는 함수 struct Function0 { let closure: () -> R private func trigger() -> R { return closure() } static func |>> (_ a: Function0, _ param: ()) -> R { return a.trigger() } static func <|(_ function: Function0, _ param: ()) -> () -> R { return function.closure } static func |>(_ f :Function0, _ closure : @escaping (R) -> R2 ) -> Function0 { let result = { closure(f.trigger()) } return Function0(closure: result) } } // 인자가 1개 있는 함수 struct Function1 { let closure: (A) -> R private func curry(_ a: A) -> Function0 { let result = { self.closure(a) } return Function0(closure: result) } fileprivate func trigger(_ a: A) -> R { return closure(a) } // 인자 하나를 받아 인자 하나가 적은 Function객체를 반환한다. static func |> (_ f :Function1, _ a: A) -> Function0 { return f.curry(a) } // 필요한 인자를 Tuple 형태로 넘겨받아 실행한다. static func |>> (_ a: Function1, _ param: (A)) -> R { return a.trigger(param) } // Function 객체가 가진 클로저 자체를 반환한다. static func <|(_ function: Function1, _ param: ()) -> (A) -> R { return function.closure } // 반환값을 인자로 받는 클로저를 받아서 Function 객체의 반환값의 타입을 변화시킨다. static func |>(_ f :Function1, _ closure : @escaping (R) -> R2 ) -> Function1 { let result = { a in closure(f.trigger(a)) } return Function1(closure: result) } } struct Function2 { let closure: (A, B) -> R private func curry(_ a: A) -> Function1 { let result = { b in self.closure(a, b) } return Function1(closure: result) } private func trigger(_ a: A, _ b: B) -> R { return closure(a, b) } static func |> (_ f :Function2, _ a: A) -> Function1 { return f.curry(a) } static func |>> (_ a: Function2, _ param: (A, B)) -> R { return a.trigger(param.0, param.1) } static func <|(_ function: Function2, _ param: ()) -> (A, B) -> R { return function.closure } static func |>(_ f :Function2, _ closure : @escaping (R) -> R2 ) -> Function2 { let result = { a, b in closure(f.trigger(a, b)) } return Function2(closure: result) } } struct Function3 { let closure: (A, B, C) -> R private func curry(_ a: A) -> Function2 { let result = { b, c in self.closure(a, b, c) } return Function2(closure: result) } private func trigger(_ a: A, _ b: B, _ c: C) -> R { return closure(a, b, c) } static func |> (_ f :Function3, _ a: A) -> Function2 { return f.curry(a) } static func |>> (_ a: Function3, _ param: (A, B, C)) -> R { return a.trigger(param.0, param.1, param.2) } static func <|(_ function: Function3, _ param: ()) -> (A, B, C) -> R { return function.closure } static func |>(_ f :Function3, _ closure : @escaping (R) -> R2 ) -> Function3 { let result = { a, b, c in closure(f.trigger(a, b, c)) } return Function3(closure: result) } } struct Function4 { let closure: (A, B, C, D) -> R private func curry(_ a: A) -> Function3 { let result = { b, c, d in self.closure(a, b, c, d) } return Function3(closure: result) } private func trigger(_ a: A, _ b: B, _ c: C, _ d: D) -> R { return closure(a, b, c, d) } static func |> (_ f :Function4, _ a: A) -> Function3 { return f.curry(a) } static func |>> (_ a: Function4, _ param: (A, B, C, D)) -> R { return a.trigger(param.0, param.1, param.2, param.3) } static func <|(_ function: Function4, _ param: ()) -> (A, B, C, D) -> R { return function.closure } static func |>(_ f :Function4, _ closure : @escaping (R) -> R2 ) -> Function4 { let result = { a, b, c, d in closure(f.trigger(a, b, c, d)) } return Function4(closure: result) } } struct Function5 { let closure: (A, B, C, D, E) -> R private func curry(_ a: A) -> Function4 { let result = { b, c, d, e in self.closure(a, b, c, d, e) } return Function4(closure: result) } private func trigger(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> R { return closure(a, b, c, d, e) } static func |> (_ f :Function5, _ a: A) -> Function4 { return f.curry(a) } static func |>> (_ a: Function5, _ param: (A, B, C, D, E)) -> R { return a.trigger(param.0, param.1, param.2, param.3, param.4) } static func <|(_ function: Function5, _ param: ()) -> (A, B, C, D, E) -> R { return function.closure } static func |>(_ f :Function5, _ closure : @escaping (R) -> R2 ) -> Function5 { let result = { a, b, c, d, e in closure(f.trigger(a, b, c, d, e)) } return Function5(closure: result) } } // MARK:- Function Object Maker // 클로저를 받아서 Function 객체로 만들어준다. func function(_ function: @escaping (A, B, C, D, E) -> R) -> Function5 { return Function5(closure: function) } func function(_ function: @escaping (A, B, C, D) -> R) -> Function4 { return Function4(closure: function) } func function(_ function: @escaping (A, B, C) -> R, _ a: A) -> Function3 { return Function3(closure: function) } func function(_ function: @escaping (A, B) -> R) -> Function2 { return Function2(closure: function) } func function(_ function: @escaping (A) -> R) -> Function1 { return Function1(closure: function) } func function(_ function: @escaping ()->R) -> Function0 { return Function0(closure: function) }