Тернарная операторская ассоциация

У меня возникают проблемы с пониманием концепции ассоциативности в контексте троичных операторов. В большинстве случаев троичные операторы выглядят так:

a ? b : c

В этом случае для оценки выражения ассоциативность не требуется. Хотя иногда троичные операторы являются вложенными:

a ? b : c ? d : e
a ? b : (c ? d : e) // : is right-associative

Тем не менее, вложение также может быть перевернуто

a ? b ? c : d : e
a ? (b ? c : d) : e // : is left-associative

Как лучше всего объяснить это явление? Не могли бы вы рассмотреть ассоциативность : оператор должен быть контекстно-зависимым, или я что-то здесь упускаю?

Вопрос об ассоциативности становится актуальным, когда кто-то хочет определить свой собственный троичный оператор, например, в Swift:

infix operator ? { associativity right precedence 120 }
infix operator : { associativity left precedence 130 }

1 ответ

Решение

Тернарный оператор всегда является правоассоциативным

Тернарный оператор является ассоциативным справа, как мы видим из вашего первого примера (и, как мы увидим ниже, это единственный выбор, который у нас есть, если мы хотим позволить соответствующему if-else блоки для хранения чего-либо еще, кроме выражений, которые вычисляются как логические). Обратите внимание, что ваш второй пример не оставляет ассоциативности комнаты, поэтому он не показывает пример левоассоциативности троичного оператора.

/* example 1 */
a ? b : c ? d : e 
==> { right-ass. } => a ? b : (c ? d : e), OK
==> { left-ass. } => (a ? b : c) ? d : e
/*                        |___|
                             \ not OK: since then both of these must be 
                               booleans: that is restriction we don't have */

/* example 2 */ 
a ? b ? c : d : e
==> { only-valid-splitup } => a ? (b ? c : d) : e

(a ? b ? c) : d : e
/* |___|
      \ not valid, there's no ? ? ternary operator */

a ? b ? (c : d : e)
/*         |___|
              \ not valid, there's no : : ternary operator */

Следовательно, ассоциативность троичного оператора корректна, даже если вы вкладываете выражения троичного оператора. Позаботьтесь, однако, о том, что это приводит к ухудшению читабельности кода, и это даже настоятельно рекомендуется для этого в руководстве по языку - Основные операторы

...

Однако используйте троичный условный оператор с осторожностью. Его краткость может привести к сложному для чтения коду при чрезмерном использовании. Избегайте объединения нескольких экземпляров тернарного условного оператора в один составной оператор.

Тернарный оператор: не два унарных оператора, а собственный уникальный оператор

Тернарный оператор - это специальный оператор, который не имеет прямого отношения ни к одному из других операторов в Swift; все остальные принадлежат к семействам унарных и бинарных операторов.

  • Унарные операторы...

  • Бинарные операторы...

  • Тернарные операторы работают на три цели. Как и C, Swift имеет только один троичный оператор - троичный условный оператор (a? B: c).

Из руководства по языкам - Основные операторы.

Так как нам разрешено только определять наши собственные prefix (одинарный) и infix (бинарные) операторы в Swift, я подозреваю, что вам будет довольно трудно реализовать свой собственный истинный троичный оператор, поскольку вы ограничены использованием его в качестве двух отдельных унарных инфиксных операторов ? а также :, что, естественно, не совпадает с одним троичным оператором. (Вы всегда можете посмотреть на это несколько старое сообщение в блоге Нейта Кука, объясняющее, как имитировать троичный оператор с помощью двух бинарных операторов, однако, поскольку в Swift 3 необходимо удалить каррирование, я не знаю, будет ли это возможно для будущие версии Swift).

Другие вопросы по тегам