Я знаю, что некоторые люди ответили бы на такие вещи, как “логическая логика (конечно)”, но я хочу объяснить здесь механизм, присутствующий в большинстве языков программирования. Многие люди знают, как это работает, но не все знают, как объяснить или почему это происходит.
Я говорю об оценке Маккарти, минимальной оценке или (как это более известно в мире компьютерных наук) оценке короткого замыкания.
Впервые я увидел это выражение в книге “Языки программирования”, написанной Робертом Себестой. Я думал, он собирается провести какую-то параллель с предметом электротехники. Когда я добрался до этого предмета, я заметил, что использую его почти каждый день, даже не зная точно, что я делаю.
Первый контакт
Оценка короткого замыкания выражения – это когда результат выражения определяется без необходимости вычисления всех операндов и операторов.
В качестве простого примера рассмотрим выражение:
(25 * x) * (y % 14 + 21)
.
Если значение x равно 0, то, несмотря ни на что, результат всего выражения будет равен нулю.
0 * (y % 14 +
Зная значение x, необходимо вычислить второе выражение ( |/y % 14 + 21 ) или сделать умножение между правой и левой стороной, возможно, не существует.
К сожалению, с арифметическими выражениями трудно определить, когда можно использовать этот ярлык. Однако языки программирования используют это поведение для вычисления другого типа выражения.
Вычисление логических выражений
Рассмотрим логическое выражение: x < 1 && y > 2
.
Его конечное значение не зависит от второго выражения, если x
потому что FALSE && y > 2
всегда будет FALSE, независимо от значения y
. Мы уверены в этом, потому что, следуя логической логике, обе стороны выражений &&
должны быть истинными, чтобы привести к истинному значению.
Поэтому, когда x < 0
, нам не нужно оценивать y
, константа 2, операнд >
или даже операция &&
.
В отличие от арифметических выражений, гораздо проще узнать, можем ли мы использовать этот ярлык во время выполнения нашей программы для булевых выражений.
Большинство языков программирования используют оценку короткого замыкания, включая Javascript, Ruby и Python.
Как я могу использовать оценку короткого замыкания?
Я приведу пример использования оценки короткого замыкания с использованием сравнения между Javascript и Ruby.
Вы пишете функцию, которая будет принимать один аргумент, который может быть любым, кроме null
или false
, потому что получение этих значений вызовет исключение и остановит вашу программу.
Я рубист, поэтому я бы написал что-то вроде:
def some_method(example_var) # some content that does not allow to receive an "example_var" nil or false end example_var = nil some_method(example_var) if example_var
К сожалению, этот синтаксис не существует в Javascript, но мы можем сделать что-то подобное с:
function someFunction(exampleVar) { // some content that does not allow to receive an "exampleVar" null or false } var exampleVar = null; exampleVar && someFunction(exampleVar);
В этом случае, используя преимущества оценки короткого замыкания, функция someFunction
будет выполняться только в том случае, если пример Var
не было null, undefined или false.
P.S.: Условное сообщение post if
в примере Ruby является просто синтаксисом sugar и не переводится в |/a && something(a) . Я использовал этот способ, чтобы проиллюстрировать использование оценки короткого замыкания на примере Javascript.
Двойственное поведение
Некоторые языки программирования реализуют операторы ожидания, наряду с операторами короткого замыкания, которые будут выполнять обе стороны выражения. Ruby и Javascript являются примерами языков, содержащих нетерпеливые операторы, но другие известные языки, такие как Python и Go, не включают их.
Вы можете использовать нетерпеливые операторы в Ruby и Javascript с помощью: &
и |
. Кроме того, вы можете использовать их как побитовые операторы (Go и Python тоже включают эти операторы, но так же побитово, а не нетерпеливо).
Чтобы проиллюстрировать, что я хочу этим сказать, я приведу пример Ruby с использованием нетерпеливых операторов и операторов короткого замыкания.
def some_method puts "I'm running." end example_var = false example_var && some_method # => false example_var & some_method # => I'm running; false
При использовании оператора короткого замыкания метод some_method
не выполняется, поскольку |/example_var был оценен как false. Выполнение остановилось, но при запуске с помощью оператора eager вычисляются обе части выражения (следовательно, будет выполняться метод
some_method ).
Какова цель оценки короткого замыкания?
Вероятно, вы думаете о том, какова цель этой оценки короткого замыкания, и я объясню на другом примере.
Предположим, вы создаете цикл для поиска индекса значения в массиве, используя while
в Java, и по ошибке используете одиночный &
для оценки вашего условия.
Java – один из языков с двойным поведением, и вы можете использовать &
в качестве оператора ожидания и & &
в качестве оператора короткого замыкания, как мы видели при использовании Ruby.
Версия кода может быть:
public class JavaExample { public static void main(String []args){ int[] list = {1, 2, 3, 4, 5}; int listen = list.length; int key = 6; int index = 0; while((index < listen) & (list[index] != key)) index = index + 1; } } # $ javac JavaExample.java # $ java -Xmx128M -Xms16M JavaExample # Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6 at JavaExample.main(JavaExample.java:9)
Поскольку оценка короткого замыкания не используется, будут выполнены обе стороны операции &
, независимо от того, является ли левая сторона истинной или ложной. Если key
отсутствует в list
, программа выдает исключение, указывающее, что программа пытается получить доступ к индексу вне привязки.
Та же итерация, которая содержит index
, выполнит list[listlen]
, что вызывает ошибку индексации, поскольку список объявлен со значением listlen - 1
в качестве верхнего предела индекса.
Но если вы используете обычный &&
, этого не произойдет, потому что Java использует вычисление короткого замыкания для логических выражений.
Если вы попытаетесь воспроизвести эту ошибку на таком языке, как Ruby, даже с помощью оператора eager &
вы не увидите никаких исключений, потому что по умолчанию Ruby проверяет, находится ли индекс в границах массива.
Жизнь – это не ложе из роз
Даже если оценка короткого замыкания выглядит хорошо в теории, нам нужно обратить внимание на некоторые побочные эффекты, которые могут возникнуть.
Давайте предположим, что мы используем вычисление короткого замыкания в выражении, и фрагмент выражения, содержащий побочный эффект, не вычисляется.
((х > у) || (и++)/10)
В этом выражении y
изменяется только тогда, когда x
. Если бы программист предположил, что y
будет изменяться каждый раз при выполнении выражения, это привело бы к большой ошибке в конечном результате программы.
Вывод
Если вы хотите углубиться, вы можете проверить формализацию логики короткого замыкания на основе Условие Хоара
Вот и все! Я надеюсь, что вы узнали что-то об оценке короткого замыкания, и я желаю, чтобы полученные знания внесли свой вклад в вашу жизнь программиста.
Пожалуйста, оставьте комментарий!
Оригинал: “https://dev.to/jeduardo824/do-you-know-how-your-language-evaluate-boolean-expressions-3fec”