Идиомы использования макросов в Лиспах

В популярных языках программирования вычисления этапа компиляции кода либо строго ограничены, либо выражаются в специальных и зачастую неудобных в использовании метаязыках. Лиспы же благодаря своему примитивному синтаксису и гомоиконичности позволяют использовать для метапрограммирования самый обычный код.

Соответствующий механизм здесь называется макросами. Макросы это функция, получающая на вход код структуры данных, и меняющая ее по своему усмотрению, и возвращающая видоизмененный код (тоже как структуру данных). После выполнения (раскрытия) макроса интерпретатор исполнит получившийся код:

(defmacro evaluate-left-only (left-form right-form)
    left-form)
(evaluate-left-only (print t) (print nil))
;;;; evaluating (print t)
;; => t

В примере мы ввели два макроса. Первый макрос (evaluate-left-only) передает, не меняя, интерпретатору свой левый аргумент (left-form), который и вычисляется, выводя t.

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

Опытные программисты на Лиспах с подозрением относятся к безудержному использованию макросов, используя их только в общепринятых случаях, о некоторых из которых я и хочу рассказать. Другими словами, это пост о паттернах использования макросов.

Немного прикладной макрологии…

Книга: Semantics with Applications

Мои познания о формальном подходе к семантике языков програмирования в лучшем случае поверхностны, но повода их углубить, в общем-то, до сих пор не было. Но тут попалась вводная книга по семантике языков программирования: Semantics with Applications.

Впечатления о книге…

Статья: ORBIT: An Optimizing Compiler for Scheme

Мир традиционных Лиспов делится на два больших семейства: родственники Common Lisp и многочисленные реализации Scheme. Common Lisp был разработан соответствующим комитетом как компромисс между многочисленными промышленными Лиспами 70-х и 80-х. И, как типичный управляемый комитетом стандарт, ANSI Common Lisp страдает многословностью и противоречивостью, что выражается в тысяче с лишним страниц определения языка.

Стандарты базовой Схемы занимают каждый порядка сотни страниц, определяя простое и легкое в реализации и понимании ядро языка. Но есть проблема: стандарт не очень практичен, и не включает в себя скучные частные вопросы. Ну, вроде стандартной библиотеки для работы с регулярными выражениями…

Тем не менее, лаконичность и простота Схемы привела к тому, что в среде академиков и энтузиастов создание эффективных интерпретаторов и компиляторов Схемы стало чем-то вроде спорта: мелких реализаций разве что не сотни, крупных — десятки. В них обкатываются новые техники компиляции функциональных и динамических языков, проверяются подходы к проблемам отрасли и просто развлекаются скучающие программисты.

Первая экспериментальная реализация компилятора Scheme была описана Гаем Стилом (англ. Guy Steele еще в конце семидесятых (см. публикацию Rabbit: A Compiler for Scheme, 1978 год). Но первым практичным компилятором стал Orbit, ключевая работа по которому была опубликована только в 1986 году.

Orbit оказал огромное влияние на все последующие компиляторы функциональных языков, в том числе Haskell, SML/NJ и многие другие, поэтому знакомство показалось мне обязательным. Во время двухдневного полета в Мюнхен у меня нашлось (много!) времени на чтение той самой первой публикации (ORBIT: An Optimizing Compiler for Scheme, длиной в 16 страниц), и получившиеся заметки хотелось бы сохранить в блоге.

Выход на Orbit-у

Курсы по системному программированию с Майклом Керриском

Всю прошлую неделю я провел в Мюнхене, на интереснейших курсах по системному программированию под Линуксом (Linux/UNIX System programming).

Приключение это далось непросто: надо было убедить начальство (Артем, огромное спасибо!) профинансировать в индивидуальном порядке недешевые занятия и поездку; дождаться самих курсов, до последнего момента остававшихся под вопросом; и, наконец, преодолеть жуткий ураган, из-за которого перелет из Лондона в Мюнхен занял два дня (вместо полутора часов). Удалось даже встретиться со старыми друзьями, с которыми довелось работать над большими вьетнамским поиском (спасибо за теплый прием, Саша!).

/images/system-programming-study.jpg

И оно стоило того. …

Книга: Compiling with Continuations

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

Один из таких выдающихся авторов — Эндрю Аппель, специалист по компиляторам в целом и компиляторам функциональных языков в частности. Его книги и ключевые научные публикации по качеству прозы — и красоте идей! — можно сравнить только с интересным романом. Книгу Modern Compiler Implementation in ML («тигровую книгу», по обложке), например, я читал раза три и, вероятно, еще не раз к ней вернусь.

Но Аппель прославился не только популярным учебником. Другая его книга, Compiling with Continuations, популяризовала и сделала стандартом в мире компиляторов функциональных языков внутреннее представление в стиле передачи продолжений (англ. continuation passing style). Ее я читал и перечитывал в последние недели.

О классике…

Книга: Essentials of Programming Languages

После прочтения Lisp in Small Pieces мне захотелось ознакомиться с другой классической книгой по языкам программирования: Essentials of Programming Languages от Даниэля Фридмана (англ. Daniel Friedman) и компании. Книга оказалась толковой, поэтому хочется хотя бы несколько слов о ней написать.

/images/book-essentials-of-programming-langs.jpg

О языках, доступно…

Январь 2020 в ретроспективе

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

Планы на год…

Я, еще раз я и мой маленький Лисп

Пару недель назад я делился впечатлениями от книги Lisp in Small Pieces, посвященной всяким деталям реализации Лиспов и Схем. LiSP и Essentials of Programming Languages (обзор которой обязательно напишу чуть позже) понадобились для небольшого предметно-ориентированного языка в одной из наших специализированных баз данных.

Уже в самых ранних научных публикациях по лиспостроению было принято демонстрационные языки писать на самом Лиспе. Интерпретаторы в этом стиле называются мета-круговыми или метациркулярным (калька с англ. metacircular). Выглядят такие интерпретаторы наглядно и лаконично, так как автоматически снимаются «несущественные» вопросы вроде работы с памятью, синтаксического анализа и т. д.

Чтобы понять масштаб проблемы я набросал небольшой лисп на C, использующий точную сборку мусора и самописный парсер; на этом примере и собрал предварительную пару шишек.

Про грабли лиспописателя…

Лямбда-исчисление на пальцах

За последние месяцы перечитал несколько книг по теории языков программированию, реализации Лиспов и основам функционального программирования. В какой-то момент я понял, что некоторые базовые вещи, связанные с лямбда-исчислением\(\lambda\)-исчисление»), у меня постоянно вылетают из головы. Этим постом я постараюсь прояснить для себя и немногочисленных читателей основные идеи, на которые опирается теория функциональных языков программирования.

Лямбда-исчисление в изложении программиста…

Книга: Lisp in Small Pieces

Как и обещал, начинаю по-немногу переводить личный блог на околотехнические рельсы. И начну с впечатлений от книги Lisp in Small Pieces за авторством Кристиана Кеннека (англ. Christian Queinnec):

/images/book-lisp-in-small-pieces.jpg

Про кусочки Лиспа…