Jean-Philippe Pellet
Jean-Philippe Pellet

Reputation: 59994

Can I use a function stored in a variable as operator in Swift?

In Swift, I'm interested in defining a custom operator whose implementation I may want to change depending on the context. Basically, I'd like to do this:

infix operator <-> {} // define the operator <->

Then, at some point in my code:

let <-> : (Int, Int) -> Int = (+)  // say that here, <-> means +
2 <-> 5 // obtain 7

I still want to be able to define <-> differently (and, possibly, for other argument types) in some other parts of the code. And I don't want to declare funcs, as the assigned function will itself actually come from an external function call.

In Swift 1.2, this fails with the error “Expected pattern” in the definition of the <-> constant.

What am I doing wrong? What are the alternatives?

Upvotes: 0

Views: 192

Answers (2)

Aky
Aky

Reputation: 1817

I feel what you're trying to achieve with a let binding shouldn't in the first place be expected to work (while being consistent with the rest of Swift)... I don't know enough PL theory to express my view properly, but something along the lines that when you declare a name with let or var, you specify the type beforehand (and the type stays fixed once you've declared it), but here you don't know the actual type until the arguments are actually passed.

This doesn't answer you question but - if it's syntactic sweetness you're after - here's some code I came up with that kind of allows you to "infixify" functions. (Haven't really tested it though, you might need to tweak the precedences and what-not. It's more tongue-in-cheek than anything else.)

func ~<T, U, V>(left: T, f: (T, U) -> V) -> (U -> V) {
    return { y in f(left, y) }
}

func ~<U, V>(g: U -> V, right: U) -> V {
    return g(right)
}

var plus = {(a: Int, b: Int) in a + b }

2~plus~2 // 4

[1, 2, 3, 4, 5, 7, 8]~contains~{$0 == 6} // false


let dot: ([Double], [Double]) -> Double = { v1, v2 in
    return reduce(lazy(Zip2(v1, v2)).map(*), 0, +)
}

func dot: ([Int], [Int]) -> Int {
return 0 // "fake" dot product
}
[1, 2, 3, 4]~dot~[2, 3, 4, 5] // 0
[1.0, 2, 3, 4]~dot~[2, 3, 4, 5] // 40.0

Upvotes: 1

David Berry
David Berry

Reputation: 41226

The best I can come up with is something like:

infix operator <-> {} // define the operator <->

func <-> (lhs:Int, rhs:Int) -> Int {
    return arrowFunction(lhs, rhs)
}

let arrowFunction : (Int, Int) -> Int = (+)

println("\(2 <-> 7)")

Upvotes: 1

Related Questions