【问题标题】:Curried infix operators in swift. Is it possible?swift 中的柯里化中缀运算符。是否可以?
【发布时间】:2014-11-16 23:49:15
【问题描述】:

我正在尝试实现函数组合。一开始我定义了一个名为compose的函数。

func compose<A,B,C>(f:(B -> C))(g: (A -> B)) -> A -> C {
    return { f(g($0)) }
}

这很好用。例如,如果我有 notisEven 之类的函数

func not(value: Bool) -> Bool {
    return !value
}

func even(value: Int) -> Bool {
    return value % 2 == 0
}

odd 函数可以用noteven 来定义,如下所示:

func odd(value: Int) -> Bool {
    return compose(not)(isEven)(value)
}

然后我决定使用自定义运算符而不是 compose 函数。自定义运算符为..。起初我只是复制了compose 函数并将其名称更改为..。下面是它的样子:

infix operator .. { associativity left }
func ..<A,B,C>(f:(B -> C))(g: (A -> B)) -> A -> C {
    return { f(g($0)) }
}

这里 Xcode 给出错误:“一元运算符实现必须有 'prefix' 或 'postfix' 修饰符”

之后我把操作符改成这样:

infix operator .. { associativity left }
func ..<A,B,C>(f: (B -> C), g: (A -> B)) -> A -> C {
    return { f(g($0)) }
}

odd 作用于:

func odd(value: Int) -> Bool {
    return (not..even)(value)
}

或者作为闭包:

let odd = not..even

这段代码有效。现在我知道在这里使.. 运算符柯里化可能没有任何好处,但我想知道为什么不允许柯里化运算符?例如,如果+ 操作符被定义为柯里化函数,我们会做这样的事情:

let array = [1,2,3,4]
array.map((+1))

【问题讨论】:

    标签: swift operator-overloading currying


    【解决方案1】:

    您要求的是称为运算符部分的东西,或者是在左侧或右侧部分应用二元运算符的能力。不幸的是,Swift 只允许完全非柯里化的运算符,这意味着你必须要有一点创意。如果我们将运算符视为二元函数op : (A, A) -&gt; A,那么它的柯里化形式curry-op : A -&gt; A -&gt; A 只是一个返回一元函数的一元函数。我们可以使用自定义的前缀和后缀运算符来模拟这个,分别模拟左右切片。

    这里是前缀和后缀+

    prefix func +<A : protocol<IntegerLiteralConvertible, IntegerArithmeticType>>(r : A) -> (A -> A) {
        return { l in l + r }
    }
    
    postfix func +<A : protocol<IntegerLiteralConvertible, IntegerArithmeticType>>(l : A) -> (A -> A) {
        return { r in l + r }
    }
    

    这可以让你编写诸如

    之类的代码
    let l = [Int](1...10) /// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    l.map(+5) /// [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
    

    而不是旧的

    l.map({ x in x + 5 })
    

    【讨论】:

    • 最后一个表达式也可以写成l.map { $0 + 5 },稍微短一点
    【解决方案2】:

    让我们为您的问题中的术语写一些(不完整的)定义:

    • 非柯里化双参数函数:接受两个参数并返回某个值的函数。示例:func add(a: Int, b: Int) -&gt; Int

    • curried 双参数函数:一个接受一个参数并返回另一个函数的函数,该函数接受一个参数并返回一些值。示例:func add(a: Int)(b: Int) -&gt; Int

    • 中缀(二进制)运算符:一个运算符,它接受两个操作数,一个lhs 和一个rhs 参数,并返回一些值。示例:func +(lhs: Int, rhs: Int) -&gt; Int

    • 前缀/后缀(一元)运算符:在运算符之后或之前采用单个操作数并返回某个值的运算符。示例:func -(x: Int) -&gt; Int

    Curried 函数更类似于一元运算符而不是二元运算符;这就是 Swift 抱怨的原因。

    【讨论】:

    猜你喜欢
    • 2016-11-26
    • 2015-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 2020-07-17
    相关资源
    最近更新 更多