커링함수 코드 만들기

Swift의 차기 버전에서는 자동 커링 함수를 만드는 기능이 제거된다고 한다.  예를 들어

func add(x: Int)(_ y:Int) -> Int { return x + y }
let plusOne = add(1)
let y = plusOne(4)
// y = 5

이런 형태로 함수를 만들 때부터 커링을 지원하도록 하던 기능이 없어진다. 커링함수는 이 기능을 쓰지 않고도 클로저를 리턴하는 함수를 이용해서 만들 수는 있다.

func curry <A, B, C>(body: (A, B) -> C) -> A -> B -> C {
    return { x in 
        { y in 
            body(x, y)
        }
    }
}

func add(x: Int, y: Int) -> Int { return x + y }
let plusOne = curry(add)(1)
let y = plusOne(4)
// y = 5

이런 커리 함수의 모양은 간단한데, 문제는 인자의 개수만큼 많은 커리 함수를 만들어야 한다는 점이다. 여간 귀찮고 (또 헷갈리는) 작업인 만큼, 이런 커리 함수 코드를 출력해주는 코드를 작성해서 25단 커링 -_- 함수까지 만들어보자.

// curry!
func makeCurryCode(num: Int) -> String? {
guard num > 1 && num < 26 else { return nil }
var typeLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters.map{ String($0) }[0num]
let genericTypeString = typeLetters.joinWithSeparator(", ")
let curriedTypeString = typeLetters.joinWithSeparator(" -> ")
let returnTypeString = typeLetters.removeLast()
let functionArgsTypeString = typeLetters.joinWithSeparator(", ")
let functionArgsString = typeLetters.map{ $0.lowercaseString }.joinWithSeparator(", ")
func makeBody(args:ArraySlice<String>) -> String {
guard !args.isEmpty else {
return "ff(\(functionArgsString))"
}
let (head, tail) = (args.first!, args.dropFirst())
return "{ \(head.lowercaseString) in \(makeBody(tail)) }"
}
return "func curry <\(genericTypeString)> (ff:(\(functionArgsTypeString)) -> \(returnTypeString)) ->"
+ " \(curriedTypeString) { return \(makeBody(typeLetters)) }"
}
Array(130).map(makeCurryCode).filter{ $0 != nil }.forEach{ print($0!) }
func curry <A, B, C> (ff:(A, B) -> C) -> A -> B -> C { return { a in { b in ff(a, b) } } }
func curry <A, B, C, D> (ff:(A, B, C) -> D) -> A -> B -> C -> D { return { a in { b in { c in ff(a, b, c) } } } }
func curry <A, B, C, D, E> (ff:(A, B, C, D) -> E) -> A -> B -> C -> D -> E { return { a in { b in { c in { d in ff(a, b, c, d) } } } } }
func curry <A, B, C, D, E, F> (ff:(A, B, C, D, E) -> F) -> A -> B -> C -> D -> E -> F { return { a in { b in { c in { d in { e in ff(a, b, c, d, e) } } } } } }
func curry <A, B, C, D, E, F, G> (ff:(A, B, C, D, E, F) -> G) -> A -> B -> C -> D -> E -> F -> G { return { a in { b in { c in { d in { e in { f in ff(a, b, c, d, e, f) } } } } } } }
func curry <A, B, C, D, E, F, G, H> (ff:(A, B, C, D, E, F, G) -> H) -> A -> B -> C -> D -> E -> F -> G -> H { return { a in { b in { c in { d in { e in { f in { g in ff(a, b, c, d, e, f, g) } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I> (ff:(A, B, C, D, E, F, G, H) -> I) -> A -> B -> C -> D -> E -> F -> G -> H -> I { return { a in { b in { c in { d in { e in { f in { g in { h in ff(a, b, c, d, e, f, g, h) } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J> (ff:(A, B, C, D, E, F, G, H, I) -> J) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J { return { a in { b in { c in { d in { e in { f in { g in { h in { i in ff(a, b, c, d, e, f, g, h, i) } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K> (ff:(A, B, C, D, E, F, G, H, I, J) -> K) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in ff(a, b, c, d, e, f, g, h, i, j) } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L> (ff:(A, B, C, D, E, F, G, H, I, J, K) -> L) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in ff(a, b, c, d, e, f, g, h, i, j, k) } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M> (ff:(A, B, C, D, E, F, G, H, I, J, K, L) -> M) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in ff(a, b, c, d, e, f, g, h, i, j, k, l) } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M) -> N) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in ff(a, b, c, d, e, f, g, h, i, j, k, l, m) } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N) -> O) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n) } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) -> P) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) } } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) -> Q) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P -> Q { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in { p in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) } } } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) -> R) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P -> Q -> R { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in { p in { q in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) } } } } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) -> S) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P -> Q -> R -> S { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in { p in { q in { r in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) } } } } } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S) -> T) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P -> Q -> R -> S -> T { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in { p in { q in { r in { s in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) } } } } } } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) -> U) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P -> Q -> R -> S -> T -> U { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in { p in { q in { r in { s in { t in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) } } } } } } } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) -> V) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P -> Q -> R -> S -> T -> U -> V { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in { p in { q in { r in { s in { t in { u in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u) } } } } } } } } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V) -> W) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P -> Q -> R -> S -> T -> U -> V -> W { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in { p in { q in { r in { s in { t in { u in { v in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v) } } } } } } } } } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W) -> X) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P -> Q -> R -> S -> T -> U -> V -> W -> X { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in { p in { q in { r in { s in { t in { u in { v in { w in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w) } } } } } } } } } } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X) -> Y) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P -> Q -> R -> S -> T -> U -> V -> W -> X -> Y { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in { p in { q in { r in { s in { t in { u in { v in { w in { x in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x) } } } } } } } } } } } } } } } } } } } } } } } } }
func curry <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z> (ff:(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y) -> Z) -> A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K -> L -> M -> N -> O -> P -> Q -> R -> S -> T -> U -> V -> W -> X -> Y -> Z { return { a in { b in { c in { d in { e in { f in { g in { h in { i in { j in { k in { l in { m in { n in { o in { p in { q in { r in { s in { t in { u in { v in { w in { x in { y in ff(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y) } } } } } } } } } } } } } } } } } } } } } } } } } }

Swift :: 1.2의 커리드함수와 함수 합성에 대해

커링

Swift 1.2부터는 커리드 함수를 만들 때 파라미터 이름을 생략할 수 있게 되었다.1 함수를 커리드함수로 정의할 때

func f(a:Int)(b:Int)(c:Int) -> Int {
    return a * 2 + b * 3 + c * 5
}

let a = f(1)
let b = a(b:2)
let c = b(c:3)

이런식으로 커리드된 함수에서는 파라미터 이름을 반드시 넣어야 했는데, 이렇게 부분적용함수의 나머지 인자에 대해 반드시 이름을 쓰는 것만 허용이 됐었다. 이 경우에는 부분적용함수를 실제로 호출하는 경우, 반드시 해당 파라미터 이름을 기술해야하므로, 원 함수의 시그니쳐를 알지못하면 쓰기가 어렵기 때문에 활용할만한 곳이 많이 않았다. 하지만 Swift 1.2에서부터 이런 제한이 없어지고, 아래와 같이 2차 이후 부터의 인자 외부 이름을 생략하는 것이 허용됐다. Swift :: 1.2의 커리드함수와 함수 합성에 대해 더보기

Swift에서 Monad와 Curried Function 사용하기

Functional Programing in Swift

Swift는 함수형 프로그래밍은 아니지만 함수형 언어들의 특성을 많이 따르고 있다. 그 중에 모나드와 커리드함수(부분적용함수)를 만드는 방법에 대해 살펴보자.

Swift에서 Monad와 Curried Function 사용하기 더보기