LINUX.ORG.RU

Сообщения komputikisto

 

Классификация операторов в Lisp

Разработчики Common Lisp не зря поменяли традиционный термин «специальная форма» на «специальный оператор». Например, выражение как целое (quote a) является специальной формой, а quote обозначает специальный оператор. Необходимо еще немного прояснить терминологию. Итак, оператор — любой объект, который может находится в голове формы. Ниже представлена классификация операторов:

                           Операторы
             _________________/\__________________________________________
	    |                              |                              |
         Функции                Специальные операторы                  макросы
       ____/\____              ____________/\________________ 
      |          |            |                              |
 встроенные   замыкания     Примитивные                 реификаторы
                        специальные операторы       ________/\_________
                                                   |                   |
                                               частичные             полные

Как можно видеть, я не отношу макросы к категории специальных операторов, т.к. макросы лишь эмулируют специальные операторы.

В соответствии с этой теорией должен быть изменен apply/eval интерпретатор:

(eval выражение окружение продолжение)
(apply-operator оператор аргументы окружение продолжение)
(apply-function функция аргументы продолжение)

Функция eval лишь вычисляет голову формы, а результат (оператор) классифицируется функций apply-operator, которая либо передает управление функции, которая реализует соответствующий специальный оператор, либо функции apply-function. Кроме того, что специальные операторы применяются к невычисленным аргументам (cdr формы), они еще имеют доступ к полному контексту вычислений. Макросы не имеют такого доступа, поэтому, я не классифицирую их как специальные операторы. Функции не имеют доступа к лексическому окружению момента вызова. Следовательно такие функции как set из CL должны рассматриваться как нарушение теории и исключены из Лиспа. Функция set может быть, но только если она будет принимать дополнительный аргумент: (set символ значение окружение).

Частичные реификторы. nlambda получает только cdr формы, vau — cdr формы и окружение.

Полные реификаторы. В работах Brian Cantwell Smith были предложены 3-х аргументные fexpr'ы. В реификаторы Смита передаются не только сырые аргументы и окружение, но и продолжение. Полные реификаторы неотличимы от встроенных специальных операторов.

 

komputikisto
()

Два подхода к контекстам

В этом посте я собираюсь рассмотреть различия в объектной модели Smalltalk и CLOS и как эти модели связаны с понятием контекста. Поклонники статической типизации могут не читать. С открытием CLOS возникли споры о том, CLOS — это что? ООП или не ООП? Становление новой науки неизбежно приводит к терминологическим спорам. ООП — термин расплывчатый и ИМХО, его следовало бы избегать. Как CLOS, так и Smalltalk реализуют одну важную фичу — ad hoc полиморфизм. Эта фича крайне важна для программирования, т.к. позволяет настраивать уже существующий код без изменения его исходного текста. Модель Smalltalk имеет ограниченный ad hoc полиморфизм, т.к. фактически позволяет производить диспетчеризацию лишь по одному аргументу. Однако, кроме ad hoc полиморфизма есть еще одна вещь, связанная с ООП — инкапсуляция. Итак, кратко опишем две ОО модели:

  • Инкапсуляция и ad-hoc полиморфизм (Smalltalk).
  • Ad-hoc полиморфизм без инкапсуляции (CLOS).

Далее я покажу, что эти два подхода противостоят друг другу. В Smalltalk объект — самодостаточная сущность. Чтобы распечатать объект (получить его внешнюю репрезентацию) необходимо послать объекту соответствующее сообщение. Это означает, что внешняя репрезентация объекта зависит только от него, и в минимальной степени зависит от внешнего контекста вызова. В CLOS внешняя репрезентация объекта целиком и полностью зависит от текущей обобщенной функции print-object. Теоретически у одного экземпляра Lisp системы может быть много различных обобщенных функций print-object.

Обычно естественные языки имеют лишь одно текстовое представление. Это не так для иероглифических языков, и скорее всего мы придём со временем к ситуации, когда один и тот же язык будет иметь множество проекций на текст. К этому же идет и эволюция языков программирования. Так, в Perl 6 функция load принимает на вход грамматику, которая описывает Perl 6 и написана на Perl 6. Далее свойство независимости от внешнего представления мы будем называть синтаксической абстракцией. ЯП, наиболее полно поддерживающий синтаксическую абстракцию — Lisp. Программы на Lisp записываются в виде S-выражений, но скобки тут нужны только для того, чтобы указать ридеру структуру. В Lisp текстовая репрезентация программы называются выражениями, а вычислитель работает не с выражениями, а с формами. Термин форма подчеркивает абстрактную природу вычислителя. Я ранее уже писал о том, как можно усилить синтаксическую абстракцию символов в Lisp.

Итак, синтаксическая абстракция предполагает, что объект, помещенный в различные контексты может иметь различные внешние представления. Модель Smalltalk не поддерживает синтаксическую абстракцию, т.к. объект сам должен вернуть свою репрезентацию в ответ на соответствующее сообщение. Давайте теперь обобщим эти рассуждения оторвав их от печати и считывания, на примере которых понятно что, инкапсуляция означает контекстную изоляцию.

Контекст — крайне важное понятие. Игнорирование контекста и абсолютизация понятий приводит к проблемам. Как определить тип объекта? Широко известен спор между Платоном и Диогеном. «Человек, - сказал Платон, - это двуногое животное без перьев». Тогда Диоген ощипал петуха и со словами: «Вот твой человек». Платону пришлось сделать уточнение: «Двуногое животное без перьев и имеющее ногти». Понятно, что тип объекта зависит от наблюдателя. Языки программирования начали с простой идеи — к каждому объекту прилеплен бейджик с его типом. В Smalltalk человеком является тот, кто на вопрос «ты кто?» отвечает — человек. Какой может быть типизация, которая учитывает контекст? Она носит название предикатная типизация. Еще иногда эту идею называют утиной типизацией. В этом подходе тип объекта зависит от того, кто и какие вопросы задает объекту. Платон может определить человека по отсутствию перьев и наличию ногтей, а Диогену нужен фонарь, чтобы определить, кто есть человек.

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

Я не отвергаю полностью концепцию инкапсуляции, но хочу обратить внимание, что ее абсолютизация (как в Smalltalk) противоречит некоторым принципам заложенным в динамические языки.

 , ,

komputikisto
()

Ищу соавтора! Реализация Lisp.

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

https://drive.google.com/file/d/0B13ti3tFkQZlSkFPV3NuMHR4eGc/view?usp=sharing

Пока исходников нет в общем доступе, т.к. я активно работаю над ними и мне тяжело будет поддерживать к ним доступ в инете. Ищу соавтора для допиливания реализации и/или написания книги по семантике Лиспа. Желательно из Санкт-Петербурга. Обращайтесь вконтакте: http://vk.com/maliculo

Еще хочу прорекламировать свою публичную лекцию в cs club по Лиспу: http://compsciclub.ru/node/2767

 

komputikisto
()

RSS подписка на новые темы