【问题标题】:Typecase regular Swift function to Curry Function将常规 Swift 函数类型化为 Curry 函数
【发布时间】:2014-11-10 01:15:47
【问题描述】:

我正在尝试将常规函数转换为 curry 函数但得到 Execution was interrupted

下面是我对函数进行柯里化并执行 unsafeBitCast 以使用一个参数调用函数并稍后使用第二个参数调用它的代码。

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)

有谁知道如何将具有两个或多个参数的常规函数​​转换为咖喱函数

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

编辑:这个例子也不起作用

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)

【问题讨论】:

  • Curry Function in Swift的可能重复
  • 该问题的解决方案是通过编写代码手动进行转换。我正在寻找一种使用 unsafeBitCast 以编程方式将常规函数类型转换为 curry 函数的方法。

标签: swift currying


【解决方案1】:

您不需要对它进行类型转换,而是返回依次捕获每个参数的嵌套闭包:

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

这样更简洁:

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

我认为写一个咖喱制造商会很有趣;就是这样 - 如果有人知道如何制作其中一个会产生令人惊叹的实际功能的人:

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

输出:

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

【讨论】:

  • 我正在寻找一种类型转换的方式。是不是不可能,如果不是,那也许就是答案。
  • 不,我不相信从一个到另一个的类型转换是可能的。
  • @EncorePTL:功能不是蔬菜——额外的成分不会做成咖喱。换句话说,柯里化是函数内部行为的一部分,而不仅仅是它的签名。除非您可以更改函数的内部行为(其源代码),否则您无法使常规函数柯里化,反之亦然。
  • @rickster 所以说我想做 autoCurry 我需要为每个可能的参数创建一个单独的函数吗? 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) } } } } }
  • 嗯,这太棒了/太可怕了,就像在 Javascript 中一样。
【解决方案2】:

对于任何感兴趣的人来说,答案是没有办法将普通函数类型转换为 curry 函数,但我解决问题的方法是通过 Nate Cook 在上面的答案中建议的 hack。这可以用于任何希望动态生成新代码并将其添加到他们的项目中的人,因为 Swift 不支持某些东西,因为它是静态类型的。如果您愿意,这也可用于手动预处理文件并在构建文件之前替换它们,并在后期处理中撤消预处理操作或生成已编译的新代码文件。

我在 Xcode 中创建了一个 Pre Build 脚本,该脚本运行一个 ruby​​ 脚本,该脚本为 2 个或更多参数(最多 10 个)生成 curry 函数。ruby 脚本是可配置的,但它会生成一个包含在项目中的 AutoCurry.swift 文件并编译到库代码中。例如这个 ruby​​ 脚本https://github.com/ankurp/Dollar.swift/blob/master/Dollar/gen_auto_curry.rb 在构建之前生成这个文件https://github.com/ankurp/Dollar.swift/blob/master/Dollar/Dollar/AutoCurry.swift

【讨论】:

    猜你喜欢
    • 2015-06-19
    • 1970-01-01
    • 2022-11-24
    • 2020-08-19
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多