iamjaph ([personal profile] iamjaph) wrote2010-12-03 08:06 am
Entry tags:

О чистоте и лени

После N-ной провальной попытки изучить Haskell и понять суть религии под названием "монадический фетишизм", решил изобрести свой "велосипед", то есть чистый и ленивый язык программирования.

Для любой открытой системы важным моментов является взаимодействие с внешним миром. В данном случаем - порядок обмена информацией.

У энергичных языков порядок определяется непосредственно самой последовательностью инструкций в программе. Напротив, для ленивых языков последовательность выполнения инструкций неопределена, а значения вычисляются по мере необходимости. Поэтому для осуществления взаимодействия с внешним миром в ленивые языки порядок вводиться искусственно.

Одним из способов упорядочивания вычислений является ввод дополнительных переменных-маркеров, при помощи которых указываются дополнительные зависимости между подпрограммами. Например, подпрограмма "C" зависит от переменной "b", которая определяется в подпрограмме "B", в свою очередь подпрограмма "B" зависит от переменной "a", значение которой определяется в подпрограмме "A", что приводит к выполнению сначала подпрограммы "A", затем "B" и лишь затем "C". Эти переменные маркеры в Mozart-OZ получили название свободные (unbound) переменные, а в Clean - уникальные типы.

Другим способом упорядочивание вычислений является использование стиля передачи продолжений. Однако этот стиль труден для использования им требует модификации подпрограмм. К счастью последнего можно избежать при помощи подпрограммы-обертки. В Haskell этой оберткой является оператор bind, а монады по сути не что иное, как своеобразный "концептуальный сахар" над стилем передачи продолжений. В свою очередь Haskell оператор do является "синтаксическим сахаром" вокруг монад, создающих иллюзию того, что переменные меняют свое значение.

Так что на самом деле Haskell, как и Clean, - абсолютно чистый язык, а религия "монадический фетишизм" - удел тех, кто на видеть разницы между иллюзией и реальностью.

P.S.
Во загнул! С другой стороны, что взять с простого физ-химика, волей случая написавшего несколько маленьких программ на Perl.

Упрощение семантики

[identity profile] nponeccop.livejournal.com 2010-12-05 05:49 pm (UTC)(link)
И ленивость, и чистота возникают из требований простоты семантики.

Семантика ленивого ЛИ проще, чем семантика энергичного ЛИ.
Семантика ЛИ проще, чем семантика ML.
Семантика языка без присваивания проще, чем семантика языка с присваиванием.
Семантика языка без побочных эффектов вообще проще, чем семантика языка без присваивания, но с вводом-выводом.

Семантика - это функция, сопоставляющая корректным программам их смыслы (результат их работы). Важно, что семантика позволяет также определить эквивалентность двух программ - две программы эквивалентны, если семантики их равны. Знание, какие программы эквивалентны, нужно как оптимизаторам, так и авторам программ. Более того, разработаны технологии т.н. абстрактной интерпретации, позволяющие почти механически конструировать анализаторы программ из математического описания семантики. Соответственно, простота семантики критична - программы с простой семантикой проще анализировать (в т.ч. человеку при написании, чтении чужой программы и рефакторингах) и проще оптимизировать, т.к. при эквивалентных преобразованиях надо проверять меньшее количество условий.

Иметь семантику ЛИ выгодно, потому что ЛИ простое и хорошо изучено. Хорошо изучено также "ЛИ с константами". Важно понимать, что мы не можем просто добавить в ЛИ константу print. Такое наивное добавление нарушит семантику, ранее эквивалентные преобразования станут неэквивалентными.

Скажем, семантика ЛИ говорит нам, что бета- и эта-преобразования (редукции и экспансии) эквивалентны. В случае констант print и ; ("последовательность экшенов") это нарушается. Также семантика говорит нам, что разные последовательности редукций одного терма отличаются в ЛИ лишь тем, что некоторые из них завершаются, а некоторые нет, а все завершающиеся последовательности редукций приводят к одинаковому результату.

Легко видеть, что терм print 2 ; print 3, в префиксной записи (;) (print 2) (print 3) не обладает таким свойством: редукции двух print местами переставлять нельзя.