Как настроить тройные операторы в Swift

Я знаю, как настроить бинарные операторы, например

infix operator ** { associativity left precedence 170 }
func ** (left: Double, right: Double) -> Double {
    return pow(left, right)
}

Но как настроить тройные операторы в Swift? Может ли кто-нибудь дать мне какую-то идею? Большое спасибо!

Ответ 1

На самом деле вы можете сделать это, объявив два отдельных оператора, которые работают вместе и используя функцию curries для одного из операторов.

Объявить трехмерный оператор x +- y +|- z, который будет проверять знак начального значения x, а затем вернуть второе значение y, если знак равен нулю или положителен, а окончательное значение z, если знак является отрицательным. То есть мы должны уметь писать:

let sign = -5 +- "non-negative" +|- "negative"
// sign is now "negative"

Начнем с объявления двух операторов. Важная роль состоит в том, чтобы иметь более высокий приоритет для второго оператора - мы сначала оценим эту часть и вернем функцию:

infix operator +- { precedence 60 }
infix operator +|- { precedence 70 }

Затем определим функции - сначала определим второй:

func +|-<T>(lhs: @autoclosure () -> T, rhs: @autoclosure () -> T)(left: Bool) -> T {
    return left ? lhs() : rhs()
}

Важная часть здесь заключается в том, что эта функция является curried - если вы вызываете ее только с помощью первых двух параметров, вместо возвращения значения T она возвращает функцию (left: Bool) -> T. Это становится вторым параметром функции для нашего первого оператора:

func +-<I: SignedIntegerType, T>(lhs: I, rhs: (left: Bool) -> T) -> T {
    return rhs(left: lhs >= 0)
}

И теперь мы можем использовать наш "троичный" оператор, например:

for i in -1...1 {
    let sign = i +- "" +|- "-"
    println("\(i): '\(sign)'")
}
// -1: '-'
// 0: ''
// 1: ''

Примечание: Я написал сообщение в блоге по этому вопросу с другим примером.

Ответ 2

"Истинный" тернарный оператор, такой как _ ? _ : _, требует поддержки языка. Swift позволяет создавать и настраивать только унарные и двоичные операторы.

Вы можете использовать технику в ответе @NateCook, чтобы создать пару двоичных операторов, которые вместе работают как тернарный оператор, но они все еще независимые бинарные операторы - вы можете использовать их самостоятельно. (В отличие от этого, _ ? _ : _ является только тернарным оператором, _ ? _ и _ : _ нельзя использовать индивидуально.)

Конечно, зачем останавливаться? Вы можете подключить больше бинарных операторов для создания четвертичных операторов и так далее. Для дополнительного кредита попробуйте сделать себе расширенного оператора космического корабля:

let c: String = a <=> b
    |<| "a < b"
    |=| "a = b"
    |>| "a > b"

(... но, пожалуйста, сделайте это только как академическое упражнение, или кто-либо другой, кто работает с написанным вами кодом, будет вас ненавидеть.)