The definition of the multiply symbol is this.
public func *(lhs: Int, rhs: Int) -> Int
I can use it in a function, like this.
func productUsingReduce(xs: [Int]) -> Int {
return xs.reduce(1, { x,y in x * y})
}
or simply like this.
func productUsingReduce(xs: [Int]) -> Int {
return xs.reduce(1, *)
}
If I try to define the same thing with a different name.
func yes(lhs: Int, rhs: Int) -> Int {
return lhs * rhs
}
I get a compiler error when I try to use it like this.
func productUsingReduce(xs: [Int]) -> Int {
return xs.reduce(1, { x,y in x yes y})
}
Why?
And why doesn't the following sytnax compile?
func productUsingReduce(xs: [Int]) -> Int {
return xs.reduce(1, { x, y in *(lhs: x, rhs: y) })
}
Your function func yes(.. is just a standard function.
To define an operator you have to declare the operator
infix operator yes
and the corresponding function
func yes(lhs: Int, rhs: Int) -> Int {
return lhs * rhs
}
But now comes the bad news: You cannot use alphanumeric characters as operators.
* definition is made of two parts:
The method definition (in Swift.Math.Integers, Swift.Math.Floating and so on)
public func *(lhs: Int, rhs: Int) -> Int
and its operator behavior (in Swift, you can write import Swift in Xcode and CMD+click on it to access the file)
infix operator * : MultiplicationPrecedence
The last snippet makes * an infix operator, so you can only use it in infix form.
About your yes function, you cannot make it behave as an operator. While you can define your own custom operators, they can only contain certain characters. As per the language specification:
Custom operators can begin with one of the ASCII characters /, =, -, +, !, *, %, <, >, &, |, ^, ?, or ~, or one of the Unicode characters defined in the grammar below (which include characters from the Mathematical Operators, Miscellaneous Symbols, and Dingbats Unicode blocks, among others). After the first character, combining Unicode characters are also allowed.
So you have to use it its standard function form.
But you could do
func ^^^(lhs: Int, rhs: Int) -> Int {
return lhs * rhs
}
infix operator ^^^
and that would work as expected
3 ^^^ 2 // 6
Related
I want define a new function for Int, which I can do the same job like +, the function name is plus, as far as I see in the codes, I made no mistake but I believe I have to take some more steps that Swift accept this function as a math function, Swift throw me compiler error like this: can not find "plus"
need help for overcome to issue, thanks.
extension Int {
static func plus (lhs: Int, rhs: Int) -> Int {
return lhs + rhs
}
}
use case:
let value: Int = 1 plus 2
ps: I know that plus is under group of Int, but I want it be accessible alone.
You can use symbols to override operators like following. But you need to define precedencegroup first and then create infix operator. Infix operator works with left hand side and right hand side.
precedencegroup SumOperatorPrecedence {
lowerThan: MultiplicationPrecedence
higherThan: AdditionPrecedence
associativity: left
assignment: false
}
infix operator *&:SumOperatorPrecedence
extension Int {
static func *&(lhs: Int, rhs: Int) -> Int {
return lhs + rhs
}
}
let f = 2 *& 3
If you want to add a number with itself, then you can do this:
extension Int {
func plus (rhs: Int) -> Int {
return self + rhs
}
}
Now, you can call it on any Integer. Like:
2.plus(rhs: 10) // prints 12
I want to define a new operator and multiply each element of the array [Int] by Int, such as [3, 2, 10] * 10.
However, because Int is neither protocol nor class (it's struct), I first defined the following:
protocol Numeric {}
extension Int: Numeric {}
extension Double: Numeric {}
extension Float: Numeric {}
And then, I tried defining the operator, like:
func *<T: Numeric> (left: [T], right: T) -> [T] {
var newArray: [T] = []
for i in left {
newArray.append(i * right)
}
return newArray
}
However, this spits out an error: Cannot convert value of type 'T' to expected argument type '[_]'.
I'm not sure what the type [_] means, which I don't expect, but I guess the problem comes from that I don't have an operator defined that takes T and T, both of which are Numeric in this case.
So I defined another operator, like:
func *<T: Numeric> (left: T, right: T) -> T {
return left * right
}
However, while this has been compiled without problems, the runtime error occurred with a lot of a lot of static * infix <A where ...> (A, A) -> A.
I'm not sure why this operator was executed so many times, but now I wonder if it is possible in the first place to define a custom * operator, although the Int does already have * operator defined.
So is it still possible to define [Int] * Int operator in Swift?
You have to require the multiplication operation in the Numeric
protocol:
protocol Numeric {
func *(lhs: Self, rhs: Self) -> Self
}
Otherwise the multiplication in newArray.append(i * right) is
not defined.
Your
func *<T: Numeric> (left: T, right: T) -> T {
return left * right
}
(which calls itself recursively, resulting in a stack overflow) is then not needed.
The implementation of your new operator itself can be simplified
(as already described in a now deleted answer) to
func *<T: Numeric> (left: [T], right: T) -> [T] {
return left.map { $0 * right }
}
Can I somehow send the mathematical sign (+, -, *) as function parameters? I want to call reduce() function for different sign.
In swift signs are functions name for a specified mathematic operation. To pass sign as parameter the parameter type must be function that takes two numbers and return a number. If you command + click on any sign you will see its definition as follow :
public func +(lhs: UInt8, rhs: UInt8) -> UInt8
public func +(lhs: Int8, rhs: Int8) -> Int8
public func +(lhs: UInt16, rhs: UInt16) -> UInt16
public func +(lhs: Int16, rhs: Int16) -> Int16
public func +(lhs: UInt32, rhs: UInt32) -> UInt32
public func +(lhs: Int32, rhs: Int32) -> Int32
public func +(lhs: UInt64, rhs: UInt64) -> UInt64
public func +(lhs: Int64, rhs: Int64) -> Int64
public func +(lhs: UInt, rhs: UInt) -> UInt
public func +(lhs: Int, rhs: Int) -> Int
In your case your reduce function should look as the following one
func reduce(sign: (Int,Int)->Int) -> Int{
return sign(2,3)
}
reduce(*)
reduce(-)
func doSomeCalculation(_ fun:((Int, Int) -> Int)) -> Int {
return fun(12,13)
}
doSomeCalculation(+) // 25
doSomeCalculation(-) // -1
The same can be done for UInt, the IntXX, etc.
+ is basically simply a function that takes two arguments and returns the sum of it. Since functions are objects like any other you can pass them around as such.
The same way you can pass + into reduce.
Yes, you can send any binary operator to the reduce() function, providing the original value and the elements in the collection are of the same type, and thus the operator can be applied.
Think at operators as functions/closures and you'll understand why this is possible in Swift. In fact operators are just like functions - they are named closures.
Also think at the way new operators can be added - you define a function with the operator name that takes a number of parameters equal to the operator arity.
Thus, the following is syntactically correct, and provides the expected output (6):
[1,2,3].reduce(0, combine: +)
Send as a Character, then switch to identify:
func acceptASign(sign: Character) {
switch sign {
case "+":
//do some addition
case "-":
//do some subtraction
case "*":
//do some multiplication
case "/":
//do some division
default:
break;
}
}
I'm trying to create an operator for numbers. For example an operator that increments a number by 10.
This is the code I wrote:
prefix operator +++{}
prefix operator +++<T>(inout operand: T) -> T{
operand += 10
return operand
}
There is an error with my += operator. it requires numeric operands. so I did this:
protocol Numeric {}
extension Int: Numeric {}
extension Float: Numeric {}
extension Double: Numeric {}
prefix operator +++ {}
prefix operator +++<T: Numeric>(inout operand: T) -> T {
operand += 10
return operand
}
But it failed to compile. Anybody have any ideas?
Heres a much cleaner and better way and works with everything from Int8 to CGFloat and only uses standard library types so you don't need to manually conform to your own protocol:
prefix operator +++ {}
prefix func +++<T where T: FloatingPointType, T.Stride: FloatingPointType>(inout operand: T) -> T {
operand = operand.advancedBy(T.Stride(10))
return operand
}
prefix func +++<T where T: IntegerArithmeticType, T: IntegerLiteralConvertible, T.IntegerLiteralType: IntegerLiteralConvertible>(inout operand: T) -> T {
operand = operand + T(integerLiteral: 10)
return operand
}
As #Airspeed Velocity pointed out you can also do it like this:
prefix operator +++ {}
prefix func +++<T: Strideable>(inout operand: T) -> T {
operand = operand.advancedBy(10)
return operand
}
The problem is that your Numeric protocol does not guarantee a += operator will be present.
Consider this:
// Numeric imposes no requirements, so this will compile
extension Range: Numeric { }
// but Range has no += operator, so +++ could not work
Instead, you would have to add += as a requirement of Numeric:
protocol Numeric: IntegerLiteralConvertible {
func +=(inout lhs: Self,rhs: Self)
}
Note, you also need Numeric to conform to IntegerLiteralConvertible so that you can create a 10 of the appropriate type to add to it.
Now, this compiles and runs fine, because Numeric guarantees all the features it uses will be available:
prefix operator +++{}
prefix func +++<T: Numeric>(inout operand: T) -> T {
operand += 10
return operand
}
var i = 10
+++i // i is now 20
That said, there is already a protocol that does what you need: Strideable, to which all the standard numeric types conform.
protocol Strideable {
// (actually _Strideable but don’t worry about that)
/// A type that can represent the distance between two values of `Self`.
typealias Stride : SignedNumberType
// note, SignedNumberType conforms to IntegerLiteralConvertible
/// Returns a `Self` `x` such that `self.distanceTo(x)` approximates
/// `n`.
///
/// - Complexity: O(1).
///
/// - SeeAlso: `RandomAccessIndexType`'s `advancedBy`, which
/// provides a stronger semantic guarantee.
func advancedBy(n: Self.Stride) -> Self
}
And an implementation of += that uses it:
func +=<T : Strideable>(inout lhs: T, rhs: T.Stride)
This means you can implement +++ like this:
prefix func +++<T: Strideable>(inout operand: T) -> T {
operand = operand.advancedBy(10)
return operand
}
I am trying to implement function composition. At first I defined a function that is named compose.
func compose<A,B,C>(f:(B -> C))(g: (A -> B)) -> A -> C {
return { f(g($0)) }
}
This works great. For example if I have not and isEven functions like
func not(value: Bool) -> Bool {
return !value
}
func even(value: Int) -> Bool {
return value % 2 == 0
}
The odd function can be defined in terms of not and even like this:
func odd(value: Int) -> Bool {
return compose(not)(isEven)(value)
}
Then I decided to use a custom operator instead of compose function. The custom operator is ... At first I just copied compose function and changed it name to ... Here is how it looks like:
infix operator .. { associativity left }
func ..<A,B,C>(f:(B -> C))(g: (A -> B)) -> A -> C {
return { f(g($0)) }
}
Here Xcode gives the error: "Unary operator implementation must have a 'prefix' or 'postfix' modifier"
After that I changed the operator to this:
infix operator .. { associativity left }
func ..<A,B,C>(f: (B -> C), g: (A -> B)) -> A -> C {
return { f(g($0)) }
}
And odd function to this:
func odd(value: Int) -> Bool {
return (not..even)(value)
}
Or as a closure:
let odd = not..even
And this code worked. Now I know maybe there is no benefit here to make .. operator curried here but I wonder why curried operators is not allowed? For example if + operator were defined as curried function we would make something like this:
let array = [1,2,3,4]
array.map((+1))
You're asking for something known as operator sections, or the ability to partially apply binary operators on the left or the right. Unfortunately, Swift allows only fully uncurried operators, which means you have to get a little creative. If we regard an operator as a binary function op : (A, A) -> A, then its curried form, curry-op : A -> A -> A, is simply a unary function returning a unary function. We can fake this with custom prefix and postfix operators that simulate right and left sectioning respectively.
Here's prefix and postfix +
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 }
}
This allows you to write code such as
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]
instead of the old
l.map({ x in x + 5 })
Let's write some (incomplete) definitions for the terms in your question:
non-curried two-argument function: A function that takes two arguments and returns some value. Example: func add(a: Int, b: Int) -> Int
curried two-argument function: A function that takes one argument and returns another function that takes one argument and returns some value. Example: func add(a: Int)(b: Int) -> Int
infix (binary) operator: An operator that takes two operands, an lhs and an rhs argument, and returns some value. Example: func +(lhs: Int, rhs: Int) -> Int
prefix/postfix (unary) operator: An operator that takes a single operand, either after or before the operator, and returns some value. Example: func -(x: Int) -> Int
Curried functions are more akin to unary operators than binary ones; that's why Swift is complaining.