2

I am trying to convert a regular function into curry function but getting Execution was interrupted

Below is the code where I am currying a function and doing an unsafeBitCast to call a function with one parameter and call it later with the second parameter.

func curry<T>(f: (T, T) -> T) -> T -> T -> T {
    return { a in
        typealias Function = (T) -> (T -> T)
        let fn = unsafeBitCast(f, Function.self)
        return curry(fn(a))
    }
}

func curry<T>(f: T -> T) -> T -> T {
    return { f($0) } // Throws Runtime Exception
}

func adder(x: Int, y: Int) -> Int {
    return x + y
}

let adderCurry = curry(adder)
let add1 = adderCurry(1)
add1(2)

Does anyone know how I can convert a regular function with two or more parameters into a curry function as such

func add(x: Int)(y: Int) -> Int {
  return x + y
}

EDIT: This example also does not work

func curry<T>(f: (T, T) -> T) -> T -> T -> T {
    typealias Function = T -> T -> T
    return unsafeBitCast(f, Function.self)
}

func adder(x: Int, y: Int) -> Int {
    return x + y
}

let adderCurry = curry(adder)
let add1 = adderCurry(1)
add1(2)
nbrooks
  • 18,126
  • 5
  • 54
  • 66
Encore PTL
  • 8,084
  • 10
  • 43
  • 78
  • possible duplicate of [Curry Function in Swift](http://stackoverflow.com/questions/24107191/curry-function-in-swift) – Anthony Kong Nov 09 '14 at 02:38
  • The solutions in that question are manually doing the conversion by writing code. I am looking for a programmatically way of typecasting a regular function into a curry function using unsafeBitCast. – Encore PTL Nov 09 '14 at 02:43

2 Answers2

2

You don't typecast it, you return nested closures that capture each parameter in turn:

func add(x: Int, y: Int) -> Int {
    return x + y
}

func curry<T1, T2, T3>(f: (T1, T2) -> T3) -> T1 -> T2 -> T3 {
    return {
        (t1: T1) -> T2 -> T3 in

        return {
            (t2: T2) -> T3 in

            return f(t1, t2)
        }
    }
}

let curriedAdd = curry(add)
let add3 = curriedAdd(3)
println(add3(5))
// 8

This is more succinct:

func curry<T1, T2, T3>(f: (T1, T2) -> T3) -> T1 -> T2 -> T3 {
    return { t1 in { t2 in f(t1, t2) } }
}

I thought it would be fun to write a curry maker; here it is - if anyone knows how to make one of these that generates an actual function that would be amazing:

func curryRecipe(n: Int) -> String {
    let types = join(", ", map(1...n, { "T\($0)" }))
    let returnType = join(" -> ", map(1...n, { "T\($0)" }))
    let closures = join(" in ", map(1...n, { "{ t\($0)" }))
    let braces = join(" ", Array(count: n, repeatedValue: "}"))
    return "func curry<\(types), R>(f: (\(types)) -> R) -> \(returnType) -> R {\r" +
        "    return \(closures) in f(\(types.lowercaseString)) \(braces)\r}"
}

println(curryRecipe(15))

Output:

func curry<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R>(f: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) -> R) -> T1 -> T2 -> T3 -> T4 -> T5 -> T6 -> T7 -> T8 -> T9 -> T10 -> T11 -> T12 -> T13 -> T14 -> T15 -> R {
    return { t1 in { t2 in { t3 in { t4 in { t5 in { t6 in { t7 in { t8 in { t9 in { t10 in { t11 in { t12 in { t13 in { t14 in { t15 in f(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15) } } } } } } } } } } } } } } }
}
Nate Cook
  • 92,417
  • 32
  • 217
  • 178
  • I am looking for a typecast way. Is it not possible then maybe that is the answer if it it not. – Encore PTL Nov 09 '14 at 02:46
  • No, I don't believe it's possible to typecast from one to the other. – Nate Cook Nov 09 '14 at 02:47
  • 1
    @EncorePTL: Functions aren't vegetables—extra ingredients won't make a curry. To put it another way, currying is part of a function's internal behavior, not just its signature. Unless you can change a function's internal behavior—its source code—you can't make a regular function curried or vice versa. – rickster Nov 09 '14 at 03:10
  • @rickster So lets say I want to do autoCurry do I need to create a separate function for every parameter possible? func autoCurry(f: (T, T) -> T) -> T -> T -> T { return { a in { b in f(a, b) } } } func autoCurry(f: (T, T, T) -> T) -> T -> T -> T -> T { return { a in { b in { c in f(a, b, c) } } } } func autoCurry(f: (T, T, T, T) -> T) -> T -> T -> T -> T -> T { return { a in { b in { c in { d in f(a, b, c, d) } } } } } – Encore PTL Nov 09 '14 at 03:22
  • Is there another elegant solution? – Encore PTL Nov 09 '14 at 03:22
  • @EncorePTL Note that when you write it the way you are, you're requiring all the parameters and the return value to have the same type, `T`. – Nate Cook Nov 09 '14 at 03:27
  • Unfortunately there is no eval like in Javascript – Encore PTL Nov 09 '14 at 03:27
  • 1
    Hmmm, that would be great/horrible, just like in Javascript. – Nate Cook Nov 09 '14 at 03:28
0

For anyone interested the answer is that there is NO way to typecast a normal function into curry function but the way I solved my problem is through a hack suggested by Nate Cook in the answer above. This can be used for anyone who wishes to dynamically generate new code and add it to their project because Swift does not support something due to it being statically typed. This can also be used to preprocess the files manually if you wish and replace them before build the files and on the post process undo the pre process actions or generate new code files which are compiled.

I created a Pre Build script in Xcode which ran a ruby script that generates the curry function for 2 or more parameters up to 10. The ruby script is configurable but it will generate a AutoCurry.swift file which gets included in the project and compiled into the library code. For example this ruby script https://github.com/ankurp/Dollar.swift/blob/master/Dollar/gen_auto_curry.rb generates this file https://github.com/ankurp/Dollar.swift/blob/master/Dollar/Dollar/AutoCurry.swift before building.

Encore PTL
  • 8,084
  • 10
  • 43
  • 78