首页 > 解决方案 > Swift中的非咖喱函数

问题描述

我有一个函数,它接受两个参数并返回一个值。

例如

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

下一步是使用 acurrying获取一个函数,该函数接受唯一的第一个参数并返回一个带有适当签名的闭包。另外,我写了一个类型别名以使结果类型更加清晰。

typealias EscapingClosure<A, B> = (A) -> B
func curry<A, B, C>(_ f: @escaping (A, B) -> C) -> EscapingClosure<A, (B) -> C> {
    return { (a: A) -> ((_ b: B) -> C) in
        return { (b: B) -> C in f(a, b) }
    }
}

但是后来我想起了函数,如果我将它应用于 curryied 结果,uncurry它应该返回一个默认函数签名。sum所以我尝试实现 的变体uncurry,以及我将得到的结果:

func uncarry<A, B, C>(_ f: @escaping EscapingClosure<A, (B) -> C>) -> (A, B) -> C {
    return { (a: A, b: B) -> C in
        return f(a)(b)
    }
}

但是这里有一个问题——我不能使用这个uncurry函数来对sum函数进行currying,因为uncurry只需要@escaping参数,其中curryied 函数返回一个非转义变体。

这是一个 Swift 编译器错误:

Cannot convert value of type '((A) -> Void) -> ()' to expected argument type '(_) -> (_) -> _'

有谁知道有什么方法可以uncurry在 Swift 中创建适用于 curryied 函数结果的函数。

标签: iosswiftfunctional-programming

解决方案


您的uncurry函数可以做到这一点,非咖喱函数:

let currableSum = curry(sum)
let uncurriedSum = uncurry(currableSum)

let add100 = currableSum(100)
print(add100(23)) // => 123

print(uncurriedSum(2, 2)) // => 4

问题是你误认为 uncurrying 是 unapplying。一旦您部分或完全应用了一个柯里化函数(或任何函数,就此而言),就没有机制可以返回,以获取产生结果的原始函数。

uncurry(add100) // ❌ can't "unapply" a partially applied function

想象一下,如果是这样的话。每个整数、字符串和其他值都必须记住是什么函数导致它的历史。我想不出一个单一的用例。一方面,它需要动态类型(或在 Swift 等静态语言中强制编译时强制转换),因为您无法预测产生给定结果的任意函数的签名。


推荐阅读