Эта статья требует дополнительных ссылок для проверки . ( август 2013 г. ) ( Узнайте, как и когда удалить этот шаблон сообщения ) |
Было высказано предположение , что оператор Elvis быть объединены в эту статью. ( Обсудить ) Предлагается с ноября 2020 года. |
Стратегии оценки |
---|
Оценка короткого замыкания , минимальная оценка или оценка Маккарти (после Джона Маккарти ) - это семантика некоторых логических операторов в некоторых языках программирования, в которых второй аргумент выполняется или оценивается только в том случае, если первого аргумента недостаточно для определения значения выражение: когда первый аргумент AND
функции оценивается как false
, общее значение должно быть false
; и когда первый аргумент OR
функции оценивается как true
, общее значение должно быть true
.
В языках программирования с отложенным вычислением ( Lisp , Perl , Haskell ) обычные логические операторы являются короткозамкнутыми. В других ( Ada , Java , Delphi ) доступны как короткие замыкания, так и стандартные логические операторы. Для некоторых логических операций, таких как исключающее или (XOR), короткое замыкание невозможно, потому что для определения результата всегда требуются оба операнда.
Операторы короткого замыкания, по сути, являются управляющими структурами, а не простыми арифметическими операторами, поскольку они не являются строгими . В терминах императивного языка (особенно C и C ++ ), где важны побочные эффекты, операторы короткого замыкания вводят точку последовательности - они полностью оценивают первый аргумент, включая любые побочные эффекты , перед (необязательно) обработкой второго аргумента. Алгол 68 использует процедуры для достижения определяемых пользователем операторов и процедур короткого замыкания.
Использование операторов короткого замыкания критиковалось как проблематичное:
Условные связки - « канд » и « кор » для краткости ... менее невинны, чем может показаться на первый взгляд. Например, cor не распределяет по cand : compare
- (А плавиковый шпат В) кор С с (А кор С) плавиковый шпат (В кор С);
в случае ¬A ∧ C второе выражение требует, чтобы B был определен, а первое - нет. Поскольку условные связки усложняют формальные рассуждения о программах, их лучше избегать.
Определение [ править ]
В любом языке программирования, который реализует оценку короткого замыкания, выражение эквивалентно условному выражению , а выражение эквивалентно . В любом случае x оценивается только один раз.x and y
if x then y else x
x or y
if x then x else y
Приведенное выше обобщенное определение подходит для языков со слабой типизацией, которые имеют более двух истинностных значений True
и False
, где операторы короткого замыкания могут возвращать последнее вычисленное подвыражение. В приведенной ниже таблице это называется «последним значением». Для строго типизированного языка выражение упрощается до логического случая и соответственно.if x then y else false
if x then true else y
Приоритет [ править ]
Несмотря на то, AND
имеет приоритет над OR
на многих языках, это не является универсальным свойством оценки короткого замыкания. Пример два оператора принимает тот же приоритет , и будучи левоассоциативным друг с другом является POSIX оболочка списка команд синтаксиса «s. [2] ( §2.9.3 )
Следующий простой вычислитель с написанием слева направо обеспечивает приоритет AND
over с OR
помощью a continue
:
функция short-circuit-eval ( операторы , значения ) let result : = True для каждого ( op , val ) в ( операторы , значения ): if op = "AND" && result = False продолжить else if op = "OR" && result = True обратного результата еще результат : = VAL обратного результата
Формализация [ править ]
Логика короткого замыкания, с побочными эффектами или без них, была формализована на основе условного оператора Хоара . Результатом является то, что операторы без короткого замыкания могут быть определены из логики короткого замыкания, чтобы иметь ту же последовательность оценки. [3]
Поддержка общих языков программирования и сценариев [ править ]
Язык | Нетерпеливые операторы | Операторы короткого замыкания | Тип результата |
---|---|---|---|
Расширенное программирование бизнес-приложений ( ABAP ) | никто | and , or | Логическое 1 |
Ада | and , or | and then , or else | Логический |
АЛГОЛ 68 | и, &, ∧; или, ∨ | andf, orf (оба определены пользователем) | Логический |
APL | ∧ , ∨ , ⍲ (NAND), ⍱ (ни), и т.д. | :AndIf , :OrIf | Логическое 1 |
awk | никто | && , || | Логический |
Баш | никто | && , || | Логический |
C , Цель-C | никто | && , || , ? [4] | int ( && , || ), зависимо от opnd ( ? ) |
C ++ 2 | никто | && , || , ? [5] | Логическое ( && , || ), зависимое от opnd ( ? ) |
C # | & , | | && , || , ? ,?? | Логическое ( && , || ), зависимое от opnd ( ? , ?? ) |
Язык разметки ColdFusion (CFML) | никто | AND , OR , && ,|| | Логический |
D 3 | & , | | && , || ,? | Логическое ( && , || ), зависимое от opnd ( ? ) |
Эйфелева | and , or | and then , or else | Логический |
Erlang | and , or | andalso , orelse | Логический |
Фортран 4 | .and. , .or. | .and. , .or. | Логический |
Перейти , Haskell , OCaml | никто | && , || | Логический |
Java , MATLAB , R , Swift | & , | | && , || | Логический |
JavaScript , Юлия | & , | | && , || | Последнее значение |
Лассо | никто | and , or , && ,|| | Последнее значение |
Котлин | and , or | && , || | Логический |
Лисп , Lua , Схема | никто | and , or | Последнее значение |
МАМПЫ (М) | & , ! | никто | Числовой |
Модула-2 | никто | AND , OR | Логический |
Оберон | никто | & , OR | Логический |
OCaml | никто | && , || | Логический |
Паскаль | and , or 5 , 9 | and_then , or_else 6 , 9 | Логический |
Perl | & , | | && , and , || ,or | Последнее значение |
Рубин | and , or | && , || | Последнее значение |
PHP | & , | | && , and , || ,or | Логический |
Оболочка POSIX (список команд) | никто | && , || | Последнее значение (выход) |
Python | нет [6] | and , or | Последнее значение |
Ржавчина | & , | | && , || [7] | Логический |
Болтовня | & , | | and: , or: 7 | Логический |
Стандартный ML | Неизвестный | andalso , orelse | Логический |
TTCN-3 | никто | and , or [8] | Логический |
Visual Basic .NET | And , Or | AndAlso , OrElse | Логический |
Visual Basic , Visual Basic для приложений (VBA) | And , Or | Select Case 8 | Числовой |
Язык Wolfram Language | And @@ {...} , Or @@ {...} | And , Or , && ,|| | Логический |
ZTT | & , | | никто | Логический |
1 ABAP и APL не имеют отдельного логического типа.
2 При перегрузке операторы &&
и ||
готовы возвращать любой тип.
3 Это применимо только к выражениям, оцениваемым во время выполнения, static if
и static assert
. Выражения в статических инициализаторах или константах манифеста используют активное вычисление.
4 Операторы Fortran не являются ни коротким замыканием, ни стремлением: спецификация языка позволяет компилятору выбрать метод для оптимизации.
5 ISO / IEC 10206: 1990 Extended Pascal допускает, но не требует, короткое замыкание.
6 ISO / IEC 10206: 1990 Extended Pascal поддерживает and_then
и or_else
. [9]
7Smalltalk использует семантику короткого замыкания до тех пор, пока аргументом and:
является блок (например, false and: [Transcript show: 'Wont see me']
).
8 языков BASIC, которые поддерживали операторы CASE, сделали это с помощью системы условной оценки, а не в виде таблиц переходов, ограниченных фиксированными метками.
9 Delphi и Free Pascal по умолчанию используют оценку короткого замыкания. Это может быть изменено параметрами компилятора, но, похоже, не используется широко.
Обычное использование [ править ]
Избегайте нежелательных побочных эффектов второго аргумента [ править ]
Обычный пример с использованием языка на основе C :
int denom = 0 ; if ( denom ! = 0 && num / denom ) { ... // гарантирует, что вычисление num / denom никогда не приведет к ошибке деления на ноль }
Рассмотрим следующий пример:
int a = 0 ; если ( а ! = 0 && myfunc ( b )) { do_something (); }
В этом примере оценка короткого замыкания гарантирует, что myfunc(b)
никогда не вызывается. Это потому, что a != 0
оценивается как ложь . Эта функция позволяет использовать две полезные программные конструкции.
- Если первое подвыражение проверяет, нужны ли дорогостоящие вычисления, и проверка дает ложное значение , можно исключить дорогостоящие вычисления во втором аргументе.
- Это разрешает конструкцию, в которой первое выражение гарантирует условие, без которого второе выражение может вызвать ошибку времени выполнения .
Оба показаны в следующем фрагменте кода C, где минимальная оценка предотвращает как разыменование нулевого указателя, так и выборку излишней памяти:
bool is_first_char_valid_alpha_unsafe ( const char * p ) { return isalpha ( p [ 0 ]); // SEGFAULT очень возможно с p == NULL }bool is_first_char_valid_alpha ( const char * p ) { return p ! = NULL && isalpha ( p [ 0 ]); // 1) нет ненужного выполнения isalpha () с p == NULL, 2) нет риска SEGFAULT }
Идиоматическая условная конструкция [ править ]
Поскольку минимальная оценка является частью семантического определения оператора, а не (необязательной) оптимизацией, многие шаблоны кодирования [ какие? ] стали полагаться на него как на краткую (если идиоматическую) условную конструкцию. Примеры включают:
Идиомы Perl :
some_condition или умереть ; # Прервать выполнение, если some_condition ложно some_condition и die ; # Прервать выполнение, если some_condition истинно
Идиомы оболочки POSIX : [10]
modprobe -q some_module && echo "модуль some_module установлен" || echo "some_module не установлен"
Эта идиома предполагает, что echo
это невозможно.
Возможные проблемы [ править ]
Непроверенное второе условие приводит к невыполненным побочным эффектам [ править ]
Несмотря на эти преимущества, минимальная оценка может вызвать проблемы для программистов, которые не осознают (или забывают), что это происходит. Например, в коде
если ( выражениеA && myfunc ( b )) { do_something (); }
if myfunc(b)
предполагается выполнить некоторую требуемую операцию независимо от того do_something()
, выполняется ли она, например, выделение системных ресурсов, и expressionA
оценивается как false, то myfunc(b)
не будет выполняться, что может вызвать проблемы. В некоторых языках программирования, таких как Java , есть два оператора, один из которых использует минимальную оценку, а другой - нет, чтобы избежать этой проблемы.
Проблемы с невыполненными операторами побочных эффектов можно легко решить с помощью правильного стиля программирования, т. Е. Без использования побочных эффектов в логических операторах, поскольку использование значений с побочными эффектами в оценках обычно делает код непрозрачным и подверженным ошибкам. [11]
Снижение эффективности из-за ограничений оптимизации [ править ]
Короткое замыкание может привести к ошибкам в прогнозировании переходов на современных центральных процессорах (ЦП) и резко снизить производительность. Ярким примером является высоко оптимизированный луч с выровненным по оси кодом пересечения прямоугольника при трассировке лучей . [ требуется пояснение ] Некоторые компиляторы могут обнаруживать такие случаи и генерировать более быстрый код, но семантика языка программирования может ограничивать такую оптимизацию. [ необходима цитата ]
Примером компилятора, неспособного оптимизировать для такого случая, является виртуальная машина Hotspot Java от 2012 года [12].
См. Также [ править ]
- Состояние безразличия
Ссылки [ править ]
- ↑ Эдсгер В. Дейкстра «О несколько неутешительной переписке», EWD1009-0, 25 мая 1987 г., полный текст
- ^ "Командный язык оболочки" . pubs.opengroup.org .
- ^ Ян А. Бергстра, А. Понсе, DJC Staudt (2010). «Логика короткого замыкания». arXiv : 1010.3674 [ cs.LO ].CS1 maint: использует параметр авторов ( ссылка )
- ^ Стандарт ISO / IEC 9899, раздел 6.5.13
- ^ Проект ISO / IEC IS 14882.
- ^ https://wiki.python.org/moin/BitwiseOperators
- ^ "std :: ops - Ржавчина" . doc.rust-lang.org . Проверено 12 февраля 2019 .
- ^ ETSI ES 201 873-1 V4.10.1, раздел 7.1.4
- ^ "and_then - Руководство GNU Pascal" . Gnu-pascal.de . Проверено 24 августа 2013 .
- ^ "Что означает || в bash?" . stackexchange.com . Проверено 9 января 2019 .
- ^ «Ссылочная прозрачность, определенность и разворачиваемость» (PDF) . Itu.dk . Проверено 24 августа 2013 .
- ^ Вассерман, Луи. «java - В каких случаях лучше использовать безусловное И (& вместо &&)» . Переполнение стека .