open atlas
↑ К треку
Логика с нуля LOGIC · 01 · 03

Импликация и эквивалентность: если-то, вакуумная истинность и guard clauses

p → q ложно ровно в одном случае: p истинно, q ложно. Ложное p делает правило вакуумно истинным. Обратное и противоположное НЕ равносильны импликации — равносильна контрапозиция, и каждый guard clause и ранний return в коде — это рассуждение по контрапозиции.

LOGIC Основы ◷ 17 min
Уровень
ОсновыJuniorMiddleSenior

В валидаторе чекаута была строка, выглядевшая ленивой: if (order.coupon) assertValid(order.coupon). Новичок прочёл бизнес-правило — «купон каждого заказа должен быть валиден» — и решил, что в коде дыра: заказы без купона вообще не проверяются! «Исправление» стало валить валидацию всякий раз, когда купона нет. Около 80% заказов идут без купона; выручка чекаута легла на сорок минут. Исходный код был правильным. Бизнес-правило — это импликация: ЕСЛИ у заказа есть купон, ТО он должен быть валиден. А импликация, у которой часть «если» ложна, автоматически считается истинной. Заказ без купона удовлетворяет правилу, ничего не делая. Это называется вакуумной истинностью, и она тихо лежит в основе ваших вызовов every(), guard clauses и половины ранних return.

Цель

После этого урока ты умеешь читать таблицу истинности p → q, объяснять вакуумную истинность и где она встречается в методах массива, определять контрапозицию (и почему только она равносильна импликации) и объяснять, почему guard clauses — это контрапозиция в коде.

1

Импликация p → q ложна ровно в одной строке: p истинно и q ложно. Импликация p → q читается «если p, то q». У её таблицы форма, которую стоит запомнить: ложь ровно в одной строке.

pqp → q
ИИИ
ИЛЛ
ЛИИ
ЛЛИ

Лучшая ментальная модель — обещание: «Если сдашь экзамен, куплю мороженое». Когда я нарушил слово? Только когда ты сдал, а мороженого нет — p истинно, q ложно. Ты сдал и получил: обещание сдержано. Не сдал, но мороженое всё равно купил: про этот случай я ничего не обещал. Не сдал, мороженого нет: тоже не нарушено.

2

При ложном p импликация вакуумно истинна. Две нижние строки говорят: когда p ложно, p → q истинно при любом q. Это вакуумная истинность — правило соблюдено, потому что его ни разу не проверили делом. «Если у заказа есть купон, он должен быть валиден» выполняется заказом без купона. Стандартная библиотека построена на этом: [].every(n => n > 0) возвращает true, потому что «для всех элементов n > 0» не имеет элемента, который мог бы нарушить условие. Код вида if (items.every(ok)) proceed() продолжит работу на пустом списке — обычно правильно, но это должно быть осознанным решением.

3

Импликация компилируется в !p || q в коде. Раз p → q ложна только при истинном p и ложном q, она эквивалентна !p || q:

// Правило: если у заказа есть купон, он должен быть валиден.
const satisfiesRule = (order) => !order.coupon || isValid(order.coupon);

Заказ без купона: !falsetrue — правило выполнено вакуумно. Заказ с купоном: !true || isValid(...) — вычисляется isValid. Усилить до order.coupon && isValid(...) — потребовать, чтобы купон существовал, — это другое высказывание, и именно этот баг внёс новичок.

4

Равносильна только контрапозиция; обратное и противоположное — ловушки. Из p → q строятся три родственных утверждения:

  • Обратное (converse): q → p — стрелка развёрнута. Не равносильно.
  • Противоположное (inverse): !p → !q — обе стороны отрицены. Не равносильно (то же, что обратное).
  • Контрапозиция (contrapositive): !q → !p — развёрнуто и отрицено. Равносильно — та же таблица.

Guard clauses используют это равносильство. Правило «если мы обрабатываем запрос, он должен быть аутентифицирован» (process → authed) имеет контрапозицию «если не аутентифицирован — не обрабатывать» — буквально if (!req.authed) return reject(req). Каждый ранний return исполняет одну контрапозицию, и то, что доживает до низа функции, удовлетворяет всем правилам.

Разбор примера

Перепишите правило «если пользователь премиум, он не видит рекламу» как guard clause через контрапозицию.

Правило: premium → noAds

Контрапозиция: !noAds → !premium, то есть «если пользователь видит рекламу, он не премиум».

Как guard clause в пути рендеринга:

function renderPage(user, content) {
  if (user.seesAds && user.isPremium) {
    throw new Error("Нарушен инвариант: премиум-пользователь не должен видеть рекламу");
  }
  // ... остальная логика рендеринга
}

Или на уровне контроля доступа:

function showPremiumBadge(user) {
  if (!user.isPremium) return null;   // guard clause — контрапозиция
  return <PremiumBadge />;
}

Заметьте, что не равносильно: вывод «если не видит рекламу, значит премиум» (обратное). Бесплатный триал тоже может прятать рекламу, поэтому такой вывод неверен.

Почему это работает

Почему «из лжи следует что угодно» определено как истина, а не ложь или неопределённость? Потому что универсальные утверждения должны переживать нерелевантные случаи. «Каждое кратное четырёх чётно» — очевидно верно. Формально: если x кратно 4, то x чётно, для всех x. Проверим x = 3: антецедент ложен. Если бы ложный антецедент делал импликацию ложной, x = 3 опровергал бы верную теорему о кратных четырёх — абсурд. Считать непроверенный случай истинным — единственный выбор, позволяющий правилам квантифицировать по неопрятному миру, отвечая лишь там, где они реально применимы.

Практика 0 / 5

p → q, где p = И и q = Л. Импликация И или Л?

p → q, где p = Л и q = Л. Импликация И или Л?

[].every(n => n > 0) в JavaScript — true или false?

Что равносильно p → q: (а) !p || q, или (б) p && q?

Какова контрапозиция утверждения «если идёт дождь, земля мокрая»?

Проверь себя
Викторина

Какое утверждение логически ЭКВИВАЛЕНТНО правилу «если пользователь премиум, он не видит рекламу»?

Итог

Импликация p → q — обещание, ложное ровно в одной строке таблицы истинности: антецедент истинен, консеквент ложен — условие выполнено, обещание нарушено. Она не утверждает причинности, только ограничение на значения истинности, и потому компилируется в !p || q. При ложном p импликация вакуумно истинна: правило не проверялось, значит, стоит — пустой массив проходит every(), заказ без купона удовлетворяет «если есть купон, он валиден». Усиление импликации до конъюнкции — другое, куда более сильное высказывание; разница — ровно все случаи, где p не выполняется. Из p → q строятся обратное q → p, противоположное !p → !q и контрапозиция !q → !p; равносильна лишь контрапозиция. Guard clauses обналичивают это равносильство: «если обрабатываем, то аутентифицирован» становится ранним выходом «если не аутентифицирован — отклонить», и стопка охранников оставляет низ функции в состоянии, где доказуемо выполняются все правила. Полная эквивалентность p ↔ q — лицензия свободно подставлять условия.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 5 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

Примени это

Примени этот урок в реальном проекте.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.