пятница, 25 декабря 2009 г.

Ленивость и строгость.

Начнём цикл лекций по ленивым вычислениям.
Цикл лекций окончен, задавайте Ваши вопросы.

У любой вещи может быть ровно 4 состояния, к которым можно приписать определённые риски:

  •  Не надо и не сделано. Риска нет
  •  Не надо и сделано. Риск минимален, за редкими исключениями.
  •  Надо и сделано. Всё хорошо, риска нет.
  •  Надо и не сделано. Риск высокий, единственная действительно нехорошая ситуация.

А теперь давайте посмотрим на типичный подход некоторых языков программирования. Как некогда шутили, про отличая функционального программирования от императивного:
В функциональном программировании Вы объясняете свою проблему математику, в императивном Вы объясняете ту-же самую проблему идиоту.
С ленью можно провести некоторые подобные аналогии. Неленивое программирование недалеко ушло от идиота, скажешь — сделает. Зато ленивое имеет отличительную Русскую черту — пока не припрёт делать ничего не будет.
Императивные языки программирования обычно являются неленивыми, есть паттерны вроде Синглтонов и Итераторов, но общей картины они не меняют, поскольку это сознательный уход от традиционной парадигмы в угоду производительности и удобству. Соответственно, если мы наложим поведение на шаблон, изложенный в самом начале поста, то помимо положительных результатов, мы получим вариант «Не надо и сделано». Запомним это и ненадолго отложим.

Многие функциональные языки по природе являются ленивыми. Это не обязательный критерий, но весьма полезный. Довольно сложно работать с бесконечными списками, функциями высшего порядка и прочими прелестями, если всё что написано исполняется сразу-же. Процессорные ресурсы, как и память, к сожалению, ограничены. Примером функционального ленивого языка может служить Haskell, который лишь чуть менее ленив, чем полностью, и, если его специально не пнуть, делать ничего не будет. Любое действии, которое должно быть выполнено нужно обязательно обозначить. Я бы не стал писать этот пункт в минус, так как это особенность реализации. Соответственно исключив пункт «Надо и не сделано» у нас остаётся только один вариант «Надо и сделано», который нас более чем устраивает.

Вроде бы всё хорошо и там и там, разве не так? Частично соглашусь, но отмечу лишь, что минимальный риск — это тоже риск. Любое действие в императивном языке может порождать сайд-эффекты. Изменение состояния класса, вывод во внешний мир (монитор, консоль, файл) и так далее. Огромный процентов ошибок, которые в принципе существуют, связан именно с сайд эффектами. Часто из-за того, что ненужное изменение было произведено (кинутое не вовремя событие, заранее инициализированный объект породивший утечку памяти, не вовремя запрошенный критический ресурс, породивший блокировку). В языке с ленивой структурой выполняются лишь те действия, которые необходимы для получения конкретного результата, что значительно сокращает ряд возможных ошибок, но к сожалению не до конца. Об остальном призвана позаботиться «строгость», которой обладает, например, тот-же Haskell. Всё, что вам дано извне пришло в качестве аргументов функции, которые всегда неизменяемые (на самом деле это не так, но прежде чем начать использовать что-то изменяемое, Вы десять раз подумаете, а так ли это Вам необходимо), взаимодействия со сторонним кодом практически никакого. Сложно что-то сломать, если Вам оно попросту недоступно. Это огромный плюс, значительно увеличивающий стабильность приложения.

Слишком хорошо, чтобы быть правдой, хочется сразу же спросить — а где подвох? Подвох действительно есть. Любые правила — это ограничения, которые как позволяют избежать ошибок, так сокращают размах возможного действа. Из-за этого бывает сложно, а иногда и невозможно, построить адекватную модель. Программы на Haskell являются крайне стабильными, часто переиспользуемыми, но практически всегда маленькими. Большую модель крайне сложно уместить в рамках строгих ограничений.

Единственный путь который я вижу — разделение макропрограммирования (программирования в рамках системы, создание архитектуры) и микропрограммирования (написание конкретный функций, оптимизация частей модулей). В реальной системе только таким образом можно получить хоть какой-то профит, от введения строгости, ленивости и дополнительных ограничений. Идеального мира не существует.

Комментариев нет:

Отправить комментарий