Как функции, типы и парадигмы помогают описывать программу?
Язык программирования задаёт средства записи алгоритма и модель выполнения, а функция выделяет именованное преобразование с контрактом входа и результата. Разные языки предлагают различные системы типов и парадигмы, но качество решения определяется тем, насколько явно выражены данные, зависимости и границы ответственности.
Контракт функции
Предусловие описывает допустимые аргументы, постусловие — результат и изменённое состояние. Чистая функция не меняет внешние данные и при одинаковом входе возвращает одинаковый результат, поэтому её проще тестировать. Побочный эффект допустим, если он является частью явно названной задачи.
Передача данных
Параметр может передавать значение, ссылку или объект с собственными правилами изменяемости. Нужно понимать семантику выбранного языка: изменение содержимого объекта и переназначение локальной переменной — не одно действие. Неясная передача владения рождает неожиданные связи между модулями.
Система типов
Тип ограничивает множество значений и операций. Статическая проверка обнаруживает часть несоответствий до запуска, динамическая определяет типы во время выполнения. Сильная или слабая система описывает допустимые неявные преобразования и не совпадает автоматически с делением на статические и динамические языки.
Парадигмы
Процедурный стиль организует шаги и состояние, объектный объединяет данные с поведением, функциональный подчёркивает композицию и неизменяемость, декларативный описывает требуемое свойство результата. Реальные языки часто многопарадигменны, поэтому задаче важнее выбранная модель, чем ярлык языка.
Второй язык
Перенесите знакомый алгоритм в язык с другой моделью типов или коллекций и сравните контракты, а не синтаксические скобки. Объясните, где хранится состояние, как передаются аргументы и как сообщается об ошибке. Такое сравнение раскрывает общие идеи программирования и границы конкретной реализации.
Контракт делает функцию переносимой между реализациями
Функция бинарного поиска требует отсортированную последовательность и возвращает индекс первого подходящего элемента либо специальное отсутствие. Аннотации типов описывают форму данных, но не проверяют сортировку; это семантическое предусловие остаётся в документации и тестах.
def lower_bound(values: list[int], target: int) -> int:
"""Return the first index whose value is not less than target."""
left, right = 0, len(values)
while left < right:
middle = (left + right) // 2
if values[middle] < target:
left = middle + 1
else:
right = middle
return left
assert lower_bound([1, 3, 3, 8], 3) == 1Функция чистая: не меняет вход и зависит только от аргументов. Тот же контракт можно реализовать на другом языке, даже если синтаксис, модель чисел и коллекции отличаются.
Практика: один контракт на двух языках
Запишите предусловие, постусловие и граничные случаи lower_bound, затем перенесите алгоритм на второй знакомый язык. Сравните целочисленное деление, диапазоны индексов и способ выразить отсутствие результата. Добавьте property-тест: индекс находится от 0 до n, все элементы слева меньше target, а элемент по индексу при наличии не меньше target. Объясните, какие свойства проверяет типизация, а какие остаются логикой программы.
Источники
- МФТИ: Программа вступительного испытания по информатике и информационно-коммуникационным технологиям.
- МФТИ: Пример вступительного испытания по информатике.
- Семакин И.Г., Хеннер Е.К., Шеина Т.Ю. Информатика. 11 класс. Базовый уровень.