Is it possible to define [Int] * Int using custom operator in Swift? - swift

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

Related

How do you write a protocol specifying the existence of an arithmetic operator in Swift?

Here's an example. Writing a function to multiply two doubles is pretty simple:
func MultiplyDoubles(_ x: Double, _ y: Double) {
return x * y
}
MultiplyDoubles(3,5) // returns 15
But suppose I wanted to write a generic function to do this:
func MultiplyValues<T>(_ x: T, _ y: T) {
return x * y //ERROR
}
MultiplyValues(3, 5)
But this throws an error: Binary operator '*' cannot be applied to to 'T' operands.
I understand that I'd need to write a protocol specifying that * can be applied to it, but how would I do this?
I tried doing:
protocol Multipliable {
static func *(A:Multipliable, B: Multipliable) -> Multipliable
}
func MultiplyValues<T: Multipliable>(_ x: T, _ y: T) -> Multipliable {
return x * y
}
MultiplyValues(3, 5)
Although this returns the message
error: MyPlayground.playground:15:19: error: argument type 'Int' does not conform to expected type 'Multipliable'
MultiplyValues(3, 5)
^
Research:
I've already looked at the documentation for protocols as well as the documentation for generics and for operators. I'm not writing a generic protocol, but rather a normal protocol that's meant to specify that it can be multiplied. This documentation explained how to overload operators, as well as how to create generic functions, and use protocols with generic functions, but none of them explained how to write a protocol specifying that an operator could be applied to the protocol.
You can use the existing Numeric protocol:
func multiply<T: Numeric>(_ x: T, _ y: T) -> T {
return x * y
}
But, let's imagine that such a protocol didn't exist. You can define your own and the specify which types conform to this protocol:
protocol Multipliable {
static func *(lhs: Self, rhs: Self) -> Self
}
// These types already implement the above method, so all you need to do
// is declare conformance to your protocol with an empty extension.
extension Int: Multipliable { }
extension Double: Multipliable { }
// repeat for other types as you see fit
And then you can do:
func multiply<T: Multipliable>(_ x: T, _ y: T) -> T {
return x * y
}
You can write something like this.
protocol Multipliable {
static func *(A:Self, B: Self) -> Self
}
extension Int : Multipliable {}
//You need other extensions for other numeric types...
func MultiplyValues<T: Multipliable>(_ x: T, _ y: T) -> T {
return x * y
}
MultiplyValues(3, 5)
But current Swift has some numeric protocols and you should better utilize them (as in Rob's answer).

Generic Swift Function Error Swift 3.0

func multiply<T: Strideable> (lhs: T, rhs: T) -> T {
return lhs * rhs
}
Why is this returning an error of:
No '*' candidates produce the expected contextual result result type 'T'
Found a work around by extending the * operator to the Double, Int, and Float types.
protocol Numeric {
func *(lhs: Self, rhs: Self) -> Self
}
extension Double: Numeric {}
extension Float: Numeric {}
extension Int: Numeric {}
Look into Strideable protocol, it does not have method ''. If you rather want it so that 'T' can be multiplied to another 'T', you should rather declare it in such a way that 'T' has ''.
func multiply<T: Strideable> (lhs: T, rhs: T) -> T where T:IntegerArithmetic {
return lhs * rhs
}
Or, you can also do as other answer suggests, since with this method you can only use Integers.

Regarding functions, the math symbol function * is called differently. Why?

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

How To Only Accept Numbers For An Operator Using Generics In Swift?

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
}

Curried infix operators in swift. Is it possible?

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.