Typecase regular Swift function to Curry Function

我是研究僧i 提交于 2019-12-11 03:59:10

问题


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)

回答1:


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) } } } } } } } } } } } } } } }
}



回答2:


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.



来源:https://stackoverflow.com/questions/26824338/typecase-regular-swift-function-to-curry-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!