Skip to content

Instantly share code, notes, and snippets.

@JCSooHwanCho
Last active January 14, 2020 15:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JCSooHwanCho/a2f043c8435ce973d93d77551fd67a28 to your computer and use it in GitHub Desktop.
Save JCSooHwanCho/a2f043c8435ce973d93d77551fd67a28 to your computer and use it in GitHub Desktop.
Currying Implementation with swift
//
// 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)
}
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