Last active
January 14, 2020 15:50
-
-
Save JCSooHwanCho/a2f043c8435ce973d93d77551fd67a28 to your computer and use it in GitHub Desktop.
Currying Implementation with swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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<R> { | |
let closure: () -> R | |
private func trigger() -> R { | |
return closure() | |
} | |
static func |>> (_ a: Function0<R>, _ param: ()) -> R { | |
return a.trigger() | |
} | |
static func <|(_ function: Function0<R>, _ param: ()) -> () -> R { | |
return function.closure | |
} | |
static func |><R2>(_ f :Function0<R>, _ closure : @escaping (R) -> R2 ) -> Function0<R2> { | |
let result = { | |
closure(f.trigger()) | |
} | |
return Function0<R2>(closure: result) | |
} | |
} | |
// 인자가 1개 있는 함수 | |
struct Function1<A, R> { | |
let closure: (A) -> R | |
private func curry(_ a: A) -> Function0<R> { | |
let result = { | |
self.closure(a) | |
} | |
return Function0(closure: result) | |
} | |
fileprivate func trigger(_ a: A) -> R { | |
return closure(a) | |
} | |
// 인자 하나를 받아 인자 하나가 적은 Function객체를 반환한다. | |
static func |> (_ f :Function1<A, R>, _ a: A) -> Function0<R> { | |
return f.curry(a) | |
} | |
// 필요한 인자를 Tuple 형태로 넘겨받아 실행한다. | |
static func |>> (_ a: Function1<A,R>, _ param: (A)) -> R { | |
return a.trigger(param) | |
} | |
// Function 객체가 가진 클로저 자체를 반환한다. | |
static func <|(_ function: Function1<A, R>, _ param: ()) -> (A) -> R { | |
return function.closure | |
} | |
// 반환값을 인자로 받는 클로저를 받아서 Function 객체의 반환값의 타입을 변화시킨다. | |
static func |><R2>(_ f :Function1<A, R>, _ closure : @escaping (R) -> R2 ) -> Function1<A, R2> { | |
let result = { a in | |
closure(f.trigger(a)) | |
} | |
return Function1<A, R2>(closure: result) | |
} | |
} | |
struct Function2<A, B, R> { | |
let closure: (A, B) -> R | |
private func curry(_ a: A) -> Function1<B, R> { | |
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, B, R>, _ a: A) -> Function1<B, R> { | |
return f.curry(a) | |
} | |
static func |>> (_ a: Function2<A, B, R>, _ param: (A, B)) -> R { | |
return a.trigger(param.0, param.1) | |
} | |
static func <|(_ function: Function2<A, B, R>, _ param: ()) -> (A, B) -> R { | |
return function.closure | |
} | |
static func |><R2>(_ f :Function2<A, B, R>, _ closure : @escaping (R) -> R2 ) -> Function2<A, B, R2> { | |
let result = { a, b in | |
closure(f.trigger(a, b)) | |
} | |
return Function2<A, B, R2>(closure: result) | |
} | |
} | |
struct Function3<A, B, C, R> { | |
let closure: (A, B, C) -> R | |
private func curry(_ a: A) -> Function2<B, C, R> { | |
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, B, C, R>, _ a: A) -> Function2<B, C, R> { | |
return f.curry(a) | |
} | |
static func |>> (_ a: Function3<A, B, C, R>, _ param: (A, B, C)) -> R { | |
return a.trigger(param.0, param.1, param.2) | |
} | |
static func <|(_ function: Function3<A, B, C, R>, _ param: ()) -> (A, B, C) -> R { | |
return function.closure | |
} | |
static func |><R2>(_ f :Function3<A, B, C, R>, _ closure : @escaping (R) -> R2 ) -> Function3<A, B, C, R2> { | |
let result = { a, b, c in | |
closure(f.trigger(a, b, c)) | |
} | |
return Function3<A, B, C, R2>(closure: result) | |
} | |
} | |
struct Function4<A, B, C, D, R> { | |
let closure: (A, B, C, D) -> R | |
private func curry(_ a: A) -> Function3<B, C, D, R> { | |
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, B, C, D, R>, _ a: A) -> Function3<B, C, D, R> { | |
return f.curry(a) | |
} | |
static func |>> (_ a: Function4<A, B, C, D, R>, _ param: (A, B, C, D)) -> R { | |
return a.trigger(param.0, param.1, param.2, param.3) | |
} | |
static func <|(_ function: Function4<A, B, C, D, R>, _ param: ()) -> (A, B, C, D) -> R { | |
return function.closure | |
} | |
static func |><R2>(_ f :Function4<A, B, C, D, R>, _ closure : @escaping (R) -> R2 ) -> Function4<A, B, C, D, R2> { | |
let result = { a, b, c, d in | |
closure(f.trigger(a, b, c, d)) | |
} | |
return Function4<A, B, C, D, R2>(closure: result) | |
} | |
} | |
struct Function5<A, B, C, D, E, R> { | |
let closure: (A, B, C, D, E) -> R | |
private func curry(_ a: A) -> Function4<B, C, D, E, R> { | |
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, B, C, D, E, R>, _ a: A) -> Function4<B, C, D, E, R> { | |
return f.curry(a) | |
} | |
static func |>> (_ a: Function5<A, B, C, D, E, R>, _ param: (A, B, C, D, E)) -> R { | |
return a.trigger(param.0, param.1, param.2, param.3, param.4) | |
} | |
static func <|(_ function: Function5<A, B, C, D, E, R>, _ param: ()) -> (A, B, C, D, E) -> R { | |
return function.closure | |
} | |
static func |><R2>(_ f :Function5<A, B, C, D, E, R>, _ closure : @escaping (R) -> R2 ) -> Function5<A, B, C, D, E, R2> { | |
let result = { a, b, c, d, e in | |
closure(f.trigger(a, b, c, d, e)) | |
} | |
return Function5<A, B, C, D, E, R2>(closure: result) | |
} | |
} | |
// MARK:- Function Object Maker | |
// 클로저를 받아서 Function 객체로 만들어준다. | |
func function<A, B, C, D, E, R>(_ function: @escaping (A, B, C, D, E) -> R) -> Function5<A, B, C, D, E, R> { | |
return Function5(closure: function) | |
} | |
func function<A, B, C, D, R>(_ function: @escaping (A, B, C, D) -> R) -> Function4<A, B, C, D, R> { | |
return Function4(closure: function) | |
} | |
func function<A, B, C, R>(_ function: @escaping (A, B, C) -> R, _ a: A) -> Function3<A, B, C, R> { | |
return Function3(closure: function) | |
} | |
func function<A, B, R>(_ function: @escaping (A, B) -> R) -> Function2<A, B, R> { | |
return Function2(closure: function) | |
} | |
func function<A, R>(_ function: @escaping (A) -> R) -> Function1<A, R> { | |
return Function1(closure: function) | |
} | |
func function<R>(_ function: @escaping ()->R) -> Function0<R> { | |
return Function0(closure: function) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
let result1: Int = function(max) | |
|> 10 | |
|> 5 | |
|>> () | |
print(result1) // 10 | |
let result2: Int = function(max) | |
|> 11 | |
|>> (5) | |
print(result2) // 11 | |
let maxWith12 = function(max) | |
|> 12 | |
<| () | |
print(maxWith12(18)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment