我正在尝试实现功能组合。起初我定义了一个名为compose
的函数。
func compose<A,B,C>(f:(B -> C))(g: (A -> B)) -> A -> C {
return { f(g($0)) }
}
这很有效。例如,如果我有not
和isEven
函数,例如
func not(value: Bool) -> Bool {
return !value
}
func even(value: Int) -> Bool {
return value % 2 == 0
}
可以odd
和not
定义even
函数,如下所示:
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给出错误:&#34;一元运算符实现必须有一个&#39;前缀&#39;或者&#39; postfix&#39;改性剂&#34;
之后我将操作员改为:
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
此代码有效。现在我知道也许这里没有任何好处让..
运算符在这里讨好但是我想知道为什么不允许使用curried运算符?例如,如果将+
运算符定义为curried函数,我们将使用以下内容:
let array = [1,2,3,4]
array.map((+1))
答案 0 :(得分:6)
您要求提供称为运算符部分的内容,或者在左侧或右侧部分应用二元运算符的功能。不幸的是,Swift只允许完全没有问题的运营商,这意味着你必须要有一点创意。如果我们将运算符视为二元函数op : (A, A) -> A
,那么它的curry形式curry-op : A -> A -> 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 })
答案 1 :(得分:2)
让我们为您的问题中的术语写一些(不完整的)定义:
非curried双参数函数:一个带两个参数并返回一些值的函数。示例:func add(a: Int, b: Int) -> Int
curried双参数函数:一个函数,它接受一个参数并返回另一个接受一个参数并返回一些值的函数。示例:func add(a: Int)(b: Int) -> Int
中缀(二进制)运算符:一个运算符,它接受两个操作数,一个lhs
和一个rhs
参数,并返回一些值。示例:func +(lhs: Int, rhs: Int) -> Int
前缀/后缀(一元)运算符:在运算符之后或之前接受单个操作数的运算符,并返回一些值。示例:func -(x: Int) -> Int
Curried函数更像是一元运算符而不是二元运算符;这就是斯威夫特抱怨的原因。