Common Lisp

редактировать

ANSI-стандартизованный диалект Lisp
Common Lisp
Paradigm Мультипарадигма : процедурный, функциональный, объектно-ориентированный, мета, отражающий, общий
СемействоLisp
Разработано Скоттом Фалманом, Ричардом П. Габриэлем, Дэвидом А. Мун, Кентом Питманом, Гай Стил, Дэн Вайнреб
Разработчик ANSI X3J13 комитет
Впервые появился1984 (36 лет назад) (1984), 1994 (26 лет назад) (1994) для ANSI Common Lisp
Дисциплина ввода Динамический, сильный
Область действия Лексический, необязательно динамический
OS Кросс-платформенный
Расширения имен файлов .lisp,.lsp,.l,.cl,.fasl
Веб-сайтcommon-lisp.net
Основные реализации
Allegro CL, ABCL, CLISP, Clozure CL, CMUCL, ECL, GCL, LispWorks, SBCL, Символика Common Lisp
Диалекты
CLtL1, CLtL2, ANSI Common Lisp
Под вашей
Lisp, Lisp Machine Lisp, Maclisp, Схема, Interlisp
Под регионом
Clojure, Dylan, Emacs Lisp, EuLisp, ISLISP, * Lisp, AutoLisp, Julia, Moose, R, SKILL, SubL

Common Lisp (CL) - диалект языка программирования Lisp, опубликованный в стандартном документе ANSI ANSI INCITS 226-1994 [S2008] (ранее X3.226-1994 (R1999)). Common Lisp HyperSpec, версия HTML с гиперссылками, была получена из стандарта ANSI Common Lisp.

Language Common Lisp был разработан как стандартизованный и улучшенный преемник Maclisp. К 1980-х несколько групп уже работали над разнообразными преемниками MacLisp: Lisp Machine Lisp (также известный как ZetaLisp), Spice Lisp, NIL и С-1 Лисп. Common Lisp стремился унифицировать, стандартизировать и расширить возможности этих диалектов MacLisp. Common Lisp - это не реализация, а спецификация языка . Доступно несколько реализаций стандарта Common Lisp, включая бесплатное программное обеспечение с открытым исходным кодом и проприетарные продукты. Common Lisp - это универсальный язык программирования с использованием парадигмами. Он поддерживает комбинацию процедурного, функционального и объектно-ориентированного программирования парадигм. Как язык динамического программирования, он облегчает эволюционную и инкрементную программу программного обеспечения с итеративной компиляцией в эффективные программы времени выполнения. Эта инкрементальная разработка часто выполняется в интерактивном режиме без прерывания работы приложения.

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

Common Lisp включает CLOS, объектную систему, которая поддерживает мультиметоды и комбинации методов. Часто это реализуется с помощью протокола Метаобъект.

Common Lisp расширяется с помощью стандартных функций, таких как мак Lisp (преобразование кода) и макросы чтения (анализаторы ввода для символов).

Common Lisp обеспечивает частичную обратную совместимость с Maclisp и оригинальным Lisp Джона Маккарти. Это позволяет переносить старое программное обеспечение Lisp на Common Lisp.

Содержание

  • 1 История
  • 2 Синтаксис
  • 3 Типы данных
    • 3.1 Скалярные типы
    • 3.2 Структуры данных
    • 3.3 Функции
      • 3.3.1 Определение функций
      • 3.3. 2 Определение общих функций и методов
      • 3.3.3 Пространство имен функций
      • 3.3.4 Несколько возвращаемых значений значений
    • 3.4 Другие типы
  • 4 Область действия
    • 4.1 Определители области действия
    • 4.2 Виды среды
      • 4.2.1 Глобальные
      • 4.2.2 Динамические
      • 4.2.3 Лексические
  • 5 Макросы
    • 5.1 Пример использования макроса для определения нового элемента управления структурой
    • 5.2 Захват и затенение числа
  • 6 Система условий
  • 7 Common Lisp Object System (CLOS)
  • 8 Компилятор и интерпретатор
  • 9 Примеры кода
    • 9.1 Парадокс дня рождения
    • 9.2 Сортировка списка объектов person
    • 9.3 Возведение в степень возведением в квадрат
    • 9.4 Найдите список доступных оболочек
  • 10 Сравнение с другими Lisps
  • 11 Реализации
    • 11.1 Список реализаций
      • 11.1.1 Коммерческ ие
      • 11.1.2 Свободное распространение Реализации файлов
      • 11.1.3 Другие реализации
  • 12 Приложения
  • 13 См. также
  • 14 Ссылки
  • 15 Библиография
  • 16 Внешние ссылки

История

Работа над общим Lisp начался в 1981 году после менеджера ARPA Боба Энгельмора по разработке единого стандартного диалекта Lisp сообщества. Большая часть первоначального языкового дизайна была сделана по электронной почте. В 1982 году Гай Л. Стил младший сделал первый обзор Common Lisp на симпозиуме ACM 1982 года по LISP и функциональному программированию.

Первая языковая документация была опубликована в 1984 году как Common Lisp the Language (известный как CLtL1), первое издание. Второе издание (известное как CLtL2), опубликованное в 1990 году, включило в себя множество изменений языка, внесенных в процесс стандартизации ANSI Common Lisp: расширенный синтаксис LOOP, объектная система Common Lisp, система условий для обработки ошибок, интерфейс для симпатичный принтер и многое другое. Но CLtL2 не является окончательным стандартным ANSI Common Lisp и, следовательно, не является документацией по ANSI Common Lisp. Окончательный стандарт ANSI Common Lisp был опубликован в 1994 году. С тех пор никаких обновлений стандарта не публиковалось. Различные расширения и улучшения Common Lisp (например, Unicode, Concurrency, ввод-вывод на основе CLOS) были предоставлены реализациями и библиотеками.

Синтаксис

Common Lisp - это диалект Lisp. Он использует S-выражения для обозначения как кода, так и структуры данных. Вызов функций, макроформы и специальные формы записываются в виде списков с именем оператора первым, как в этих примерах:

(+ 2 2); складывает 2 и 2, получая 4. Имя функции - «+». В Лиспе операторов как таковых.
(defvar * x *); Гарантирует, что переменная * x * существует,; не придавая ему значения. Звездочки являются частью; имя, по соглашению обозначающее специальную (глобальную) переменную. ; Символ * x * также наделяется своим: последующие привязки являются скорее динамическими, чем лексическими. (setf * x * 42.1); Устанавливает переменную * x * в значение с плавающей точкой 42.1
;; Определите функцию, возводящую число в квадрат: (defun square (x) (* x x))
;; Выполните функцию: (квадрат 3); Возвращает 9
;; Конструкция пусть создает область для локальных чисел. Вот ;; переменная 'a' привязана к 6, а переменная 'b' привязана ;; до 4. Внутри 'пусть находится' тело ', в котором возвращается последнее вычисленное значение. ;; Здесь результат a и b возвращается из сложения выражения let. ;; Переменные a и b имеют лексическую область видимости, если только символы не были ;; помечены как специальные переменные (например, предыдущим DEFVAR). (пусть ((a 6) (b 4)) (+ a b)); возвращает 10

Типы данных

Common Lisp имеет много типов данных.

Скалярные типы

Числовые типы включают целые числа, отношения, числа с плавающей запятой и комплексные числа. Common Lisp использует bignums для представления числовых значений произвольного размера и точности. Тип отношения точно представляет дроби, что не доступно на многих языках. Common Lisp автоматически сопоставляет числовые значения между этим типами по мере необходимости.

Тип символа Common Lisp не ограничен символами ASCII. Большинство современных реализаций позволяют использовать символы Unicode.

Тип символов является общим для языков Lisp, но в степени неизвестен за их пределами. Символ - это уникальный именованный объект данных, состоящий из нескольких частей: имя, значение, функция, список свойств и пакет. Из них наиболее важными являются ячейка значения и ячейка функции. Символы в Лиспе часто используются аналогично используемому языку: для хранения значений переменных; однако есть много других применений. Обычно при символе символа возвращается его значение. Некоторые символы оцениваются сами по себе, например, все символы в пакете ключевыми словами являются самооценочными ключевыми словами. Логические значения в Common Lisp представляют символами самооценки T и NIL. В Common Lisp есть пространство имен для символов, называемые «пакетами».

Существует ряд функций для округления скалярных числовых переменных способов. Функция roundокругляет аргумент до ближайшего целого числа, промежуточные округляются до четного целого числа. Функции усекают, поли потолококругляют в сторону нуля, вниз или вверх соответственно. Все эти функции возвращают отброшенную дробную часть как вторичное значение. Например, (этаж -2,5)дает -3, 0,5; (потолок -2,5)дает −2, −0,5; (округление 2,5)дает 2, 0,5; и (раунд 3,5)дает 4, -0,5.

Структуры данных

Типы последовательностей в Common Lisp списки включают, класс битовые инструкции и строки. Есть много операций, которые могут работать с любым типом работает.

Как и почти во всех других диалектах Лиспа, списки в Common Lisp состоят из conses, иногда называемых cons-ячейками или парами. Минусы - это структура данных с двумя слотами, которые называются car и cdr. Список - это связанная цепочка заключений или пустой список. Автомобиль каждого минуса относится к члену списка (возможно, другого списка). Cdr каждого потребителя относится к следующим минусам, за исключением последних минусов в списке, cdr которого относится к значению nil. Conses также можно легко использовать для реализации деревьев и других структур данных; обычно рекомендуется использовать вместо этого экземпляры хотя структуры или класса. Также возможно создать круговые структуры данных с помощью conses.

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

Хеш-таблицы хранят ассоциации между объектами данных. Любой город может Роман как ключ или значение. Размер хеш-таблиц автоматически изменяется по мере необходимости.

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

Структуры, аналогичные по использованию структурым C и надеж Pascal, произвольные сложные структуры данных с любыми и типом полей (называемых слотами). Структуры допускают одиночное наследование.

Классы похожи на структуры, но предоставляют более динамические функции и множественное наследование. (См. ЗАКРЫТЬ ). Классы были добавлены в Common Lisp поздно, и есть концептуальное совпадение со структурой. Объекты, созданные из классов, называются экземплярами. Особый случай - универсальные функции. Общие функции - это как функции, так и экземпляры.

Функции

Common Lisp поддерживает функции первого класса. Например, можно писать функции, которые также принимают другие функции в качестве аргументов или возвращают функции. Это позволяет описывать самые общие операции.

Библиотека Common Lisp в степени полагается на такие функции высшего порядка. Например, функция sortпринимает реляционный оператор в качестве аргумента и ключевую функцию в качестве необязательного аргумента ключевого слова. Это можно использовать не только для сортировки любого типа данных, но и для сортировки структур данных по ключу.

;; Сортирует список с помощью>и < function as the relational operator. (sort (list 5 2 6 3 1 4) #'>); Возвращает (6 5 4 3 2 1) (sort (list 5 2 6 3 1 4) # '<) ; Returns (1 2 3 4 5 6)
;; Сортирует список в соответствии с первым каждым подсписка. (Sort (list' (9 A) '(3 B) '(4 C)) #' < :key #'first) ; Returns ((3 B) (4 C) (9 A))

Модель оценки для функций очень проста. Когда оценщик встречает форму (f a1 a2...), он предполагает, что символ с именем f является одним из следующих :

  1. Специальный оператор (легко проверяется по фиксированному списку)
  2. Макрооператор (должен быть определен ранее)
  3. Имя функции (по умолчанию), который может быть либо символом, либо подформой, начинающейся с символ лямбда.

Если f - имя, то оцениваются аргументы a1, a2,..., в порядке слева направо, и функция будет найдена и вызвана с теми же значениями, которые указаны в параметрах параметров.

Определение функций

Макрос defun определяет функции, в которых определение функции дает имя функции, имена любых аргументов и тела функции:

(defun square ( x) (* xx))

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

(defun square (x) «Вычисляет квадрат x с одинарным числом с плавающей запятой». (Declare (single-float x) ( optimize (speed 3) (debug 0) (security 1))) (single-float (* xx)))

Анонимные функции (функциональные литералы ) с помощью лямбдавыражения, например (lambda (x) (* xx))для функции, возводящей в квадрат свой аргумент. Стиль программирования Lisp часто использует функции высшего порядка, для которых используются анонимные функции в качестве аргументов.

Локальные функции могут быть использованы с помощью fletи меток.

(flet ((square (x) (* xx))) (квадрат 3))

Там - это несколько других операторов, связанных с определением функций и управлением ими. Например, функция может быть скомпилирована с помощью оператора compile. (По умолчанию запускают функции с использованием интерпретатора, если не указано, другие функции компилируют).

Определение общих функций и методов

Макрос defgenericопределяет универсальные функции. Универсальные функции - это набор методов. Макрос defmethodопределяет методы.

Методы могут специфицировать свои параметры на стандартные классах CLOS, системные классах, классах структуры или отдельных объектов. Для многих типов существующих системных классов.

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

(defgeneric add (ab))
(defmethod add ((a number) (b number)) (+ ab))
(defmethod add ((a vector) (b number)) (map ' vector (lambda (n) (+ nb)) a))
(defmethod add ((a vector) (b vector)) (map 'vector #' + ab))
(defmethod add ((строка) (b строка)) (объединить 'строку ab))
(добавить 2 3); возвращает 5 (добавить # (1 2 3 4) 7); возвращает # (8 9 10 11) (добавить # (1 2 3 4) # (4 3 2 1)); возвращает # (5 5 5 5) (добавить «ОБЩИЙ» «LISP»); возвращает "COMMON LISP"

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

Пространство имен функций

Пространство имен для имен функций отделено от пространства имен для чисел данных. Это различие между Common Lisp и Scheme. Для Common Lisp операторы, определяющие имена в именах функций, включают defun, flet, labels, defmethodи defgeneric.

Чтобы передать функцию по имени в качестве аргумента другой функции, необходимо использовать специальный оператор function, обычно обозначаемый как # '. Первый пример sortвыше относится к функциям, названной символом >в пространстве имен функций, с кодом #'>. И наоборот, чтобы вызвать функцию, переданную таким образом, можно использовать оператор funcallдля аргумента. Модель

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

То, является ли отдельное пространство имен для функций преимуществом, является разногласий в сообществе Lisp. Обычно это называют спором Лисп-1 против Лисп-2. Lisp-1 относится к модели Схема, а Lisp-2 относится к модели Common Lisp. Эти названия были придуманы в статье 1988 г. Ричардом П. Гэбриэлем и Кентом Питманом, в котором подробно сравниваются два подхода.

Множественные возвращаемые значения

Common Lisp поддерживает концепцию множественных значений, где любое выражение всегда имеет одно первичное значение, но может также иметь любое количество вторичных значений, которые могут быть получены и проверены заинтересованными вызывающими сторонами. Эта концепция отличается от возврата значения списка, поскольку вторичные значения являются полностью необязательными и передаются через выделенный побочный канал. Это означает, что вызывающие абоненты могут оставаться в полном неведении о наличии вторичных значений, если они им не нужны, и это делает удобным использование механизма передачи информации, которая иногда бывает полезной, но не всегда необходимой. Например,

  • Функция TRUNCATEокругляет заданное число до целого в сторону нуля. Однако он также возвращает остаток в качестве вторичного значения, что позволяет очень легко определить, какое значение было усечено. Он также поддерживает необязательный параметр делителя, который можно тривиально использовать для евклидова деления :
(let ((x 1266778) (y 458)) (multi-value-bind (частное остаток) ( truncate xy) (format nil "~ A, деленное на ~ A ~ A остаток ~ A" xy частный остаток))) ;;;; =>«1266778, деленное на 458, составляет 2765, остаток 408»
  • GETHASHвозвращает значение ключа в ассоциативной карте или значение по умолчанию в противном случае, и вторичное логическое значение, указывающее, был найден. Таким образом, код, который не заботится о том, было ли значение найдено или предоставлено по умолчанию, может просто использовать его как есть, но когда такое различие важно, онможет вторичное проверить логическое значение и отреагировать соответствующим образом. Оба варианта использования поддерживаются одним и тем же вызовом, и ни один из них не обременен и не ограничен другим. Наличие этой функции на уровне языка избавляет от необходимости проверять наличие ключа или сравнивать его с null, как это было бы на других языках.
(defun get-answer (library) (gethash 'библиотека ответов 42)) (defun the-answer-1 (library) (format nil «Ответ ~ A» (библиотека get-answer))) ;;;; Возвращает «Ответ 42», если ANSWER отсутствует в БИБЛИОТЕКЕ (defun the-answer-2 (library) (multi-value-bind (answer sure-p) (get-answer library) (if (not sure-p) ») Я не знаю "(формат ноль" Ответ ~ A "ответ)))) ;;;; Возвращает" Я не знаю ", если ОТВЕТ отсутствует в БИБЛИОТЕКЕ

Несколько преимуществ поддерживаются стандартными формами, наиболее распространенными из которых являются MULTIPLE -VALUE-BINDспециальная форма для доступа к вторичным значениям и VALUESдля нескольких значений возврата:

(defun magic-8-ball () «Вернуть прогноз прогноза с вероятностью в качестве вторичного значения »(значения« Outlook хороший »(случайный 1,0))) ;;;; =>" Outlook хороший ";;;; =>0.3187

Другие типы

Другие типы данных в Common Lisp Включает:

  • Пути предоставляет файлы и каталоги в файловой системе. а Lisp к файлам широко переносимым между различными системами.
  • Потоки вывода и вывода выводят источники и приемники двоичных или текстовых данных, такие как терминал или открытые файлы.
  • Common Lisp имеет встроенный генератор псевдослучайных чисел (PRNG). Объекты случайного состояния предоставьте собой использованные источники псевдослучайных чисел, позволяя пользователю заполнить ГПСЧ или заставить его выполнить приведение последовательности.
  • Условия - это тип использования для представлений, исключений и других «интересных» событий на которые программа может ответить.
  • Классы являются объектами класса и сами являются экземплярами классов, называемыми метаобъектами (метаклассами для кратко).
  • Читаемые таблицы - это тип объекта, управляет тем, как программа Common Lisp анализирует текст исходного кода. Контролируя, какая таблица чтения используется при считывании кода, программист может изменить или расширить синтаксис языка.

Область действия

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

Связь между именем и сущностью, на которую указывает имя, называется привязкой.

Область действия относится к набору обстоятельств, при которых определено, что имя имеет определенную привязку.

Определители области действия

Обстоятельства, определяющие область действия в Common Lisp, включая:

  • расположение ссылок в выражении. Если это крайняя левая позиция соединения, это относится к специальному оператору, макросу или привязке функции, в случае прикрепления к привязке или чему-то еще.
  • тип выражения, в котором имеет место ссылка. Например, (go x)означает передачу управления метке x, тогда как (print x)относится к переменной x. Обе области xмогут быть активны в одной и той же области текста программы, поскольку метки тела тега находятся в пространстве имен, отличном от имен. Специальная форма или макроформа имеет полный контроль над значениями всех символов в ее синтаксисе. Например, в (defclass x (ab) ()), определение класса, (ab)- это список базовых классов, поэтому эти имена ищутся в имен классов, а xне является подключенным к существующей привязке, а является именем нового класса, производного от aи b. Эти факты вытекают исключительно из семантики defclass. Единственный общий факт об этом выражении - то, что defclassотносится к привязке макроса; все остальное зависит от defclass.
  • расположения ссылок в тексте программы. Например, если ссылка на переменную xзаключена в конструкцию привязки, такую ​​как let, которая определяетку для x, тогда ссылка находится в области, созданной привязкой.
  • для ссылок на переменную независимо от того, был ли переменную, локально или глобально, объявлен специальным. Это определяет, разрешается ли ссылка в лексической среде или в динамической среде.
  • конкретный экземпляр среды, в которой разрешается ссылка. Среда - это словарь времени выполнения, который сопоставляет символы привязкам. Каждый вид ссылки использует свою среду. Ссылки на лексические переменные разрешаются в лексической среде и так далее. С одной и той же ссылкой может быть связана одна среда. Например, благодаря рекурсии или использованию нескольких одновременных активаций одной и той же функции. Эти активации используют один и тот же программный текст, но имеет свой собственный экземпляр лексической среды.

понять, на что указанный символ, программист Common Lisp должен знать, какой тип ссылок выражается, какую область видимости он использует, если он - Чтобы это ссылка на переменную (динамическая или лексическая область видимости), а также ситуация во время выполнения: в какой среде разрешается ссылка, где была введена привязка в среду и т. д.

Виды среды

Глобальное

Некоторые среды в Lisp распространяются глобально. Например, если новый тип определен, он будет известен после этого. Ссылки на этот тип ищите в этой глобальной среде.

Динамическая

Одним из типов среды в Common Lisp является динамическая среда. Привязки, установленные в этой среде, имеют динамическую протяженность, что означает привязка к началу выполнения некоторой конструкции, как блок let, и исчезает, когда эта конструкция завершает выполнение: ее время жизни привязано к динамической активации и деактивации блока. Однако динамическая привязка не только видна внутри этого блока; он также виден всем функциям, вызываемым из этого блока. Этот тип видимости известен как неопределенная область видимости. Привязки, которые демонстрируют динамическую протяженность (время жизни, связанное с активацией и деактивацией блока) и неопределенную область действия (видимую для всех функций, вызываемых из этого блока), как говорят, имеют динамическую область действия.

Common Lisp поддерживает переменные с динамической областью видимости, которые также называются специальными переменными. Некоторые другие виды привязок также имеют динамическую область видимости, например, перезапуск и теги перехвата. Привязки функций не могут быть динамически ограничены с помощью fletкоторый (обеспечивает только объекты привязки функций с лексической областью видимости), но функции (объект первого уровня в Common Lisp) могут быть назначены переменным с динамической областью видимости, привязанным с С помощью letв динамической области, вызывается с помощью funcallили APPLY.

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

В Common Lisp переменная, имеющая привязку только верхнего уровня, ведет так же, как глобальная переменная на других языках программирования. В нем можно сохранить новое значение, и это значение просто заменяет то, что находится в привязке верхнего уровня. Неосторожная замена глобальных значений, связанных с ошибками, вызванными использованием глобальных чисел. Однако другой способ работы со специальной вставкой - Установите ей новую локальную привязку внутри выражения. Иногда это «повторным связыванием» называют стандартный. Привязка динамической памяти областью видимости создается новое место в памяти. Пока эта привязка работает, все ссылки на эту переменную связь к новой привязке; предыдущая привязка скрыта. Когда выполнение выражения привязки завершается, временная ячейка исчезает, и открывается старая привязка с неизменным исходным значением. Конечно, несколько динамических привязок для одной и той же модели вложенных.

Реализации Common Lisp, которые включают многопоточность, динамические области видимости специфичны для каждого потока выполнения. Таким образом, специальные переменные абстракции для локального хранилища потоков. Если один поток повторно связывает специальную переменную, это повторное связывание не влияет на эту переменную в других потоках. Значение, хранящееся в привязке, может быть получено только потоком, создавшим эту привязку. Если каждый поток связывает какую-то специальную переменную * x *, тогда * x *ведет себя как локальное хранилище потока. Среди потоков, которые не повторно связывают * x *, он ведет себя как обычный глобальный: все эти потоки связаны на одну и ту же привязку верхнего уровня * x *.

Могут and динамические переменные для Неявно передается дополнительная функция контекста, которая не появляется в качестве дополнительного расширения функций. Это особенно полезно, когда передача управления через уровни несвязанного кода. В такой ситуации обычно требуется глобальная переменная. Эта глобальная переменная должна быть сохранена и восстановлена, чтобы схема не нарушалась при рекурсии: об этом позаботится повторное сопоставление динамической переменной. И эта схема должна быть сообщена об этом сообщении.

В библиотеке Common Lisp есть много стандартных специальных чисел. Например, все стандартные потоки ввода-вывода хранятся в привязках верхнего уровня хорошо известного числа. Стандартный поток выводится в * стандартном выводе *.

Предположим, функция foo записывает в стандартный вывод:

(defun foo () (формат t «Hello, world»))

Чтобы записать свой вывод в виде строки символов, * стандартный вывод * может быть привязан к строковому потоку и вызван:

(with-output-to-string (* standard-output *) (foo))
->"Hello, world"; собранные выходные данные возвращаются в виде строки

Лексический

Common Lisp поддерживает лексические среды. Формально привязки в лексической среде имеют лексическую область действия и могут иметь неопределенную или динамическую степень, в зависимости от типа пространства имен. Лексическая область действия означает, что видимость физически ограничена блоком, в котором установлена ​​привязка. Ссылки, которые не встроены в этот блок текстуально (т. Е. Лексически), просто не видят эту привязку.

Теги в TAGBODY имеют лексическую область видимости. Выражение (GO X) ошибочно, если оно не встроено в TAGBODY, которое содержит метку X. Привязки меток исчезают, когда TAGBODY завершает свое выполнение, потому что они имеют динамическую протяженность. Если этот блок повторно вводится при вызове лексического замыкания , для тела этого замыкания недопустимо пытаться передать управление тегу через GO:

(defvar * stashed *) ;; будет функция (содержит tagbody (setf * stashed * (lambda () (go some-label))) (go end-label) ;; пропустить (print "Hello") some-label (print "Hello") end-label) ->NIL

Когда TAGBODY выполняется, он сначала оценивает формулу, которая выполняет функцию в новой * включенной *. Затем (go end-label) передает управление конечной метке, пропуская код (выведите «Hello»). Конечная метка находится в конце тела тега, тега завершается, давая NIL. Предположим, что теперь вызывается ранее запомненная функция:

(funcall * stashed *) ;; Ошибка!

Эта ситуация ошибочная. Ответом одной реализации является состояние ошибки, содержащее сообщение «GO: tagbody для тега SOME-LABEL уже оставлено». Функция попыталась оценить (go some-label), который лексически встроен в тело тега, и преобразуется в метку. Однако tagbody не выполняется (его размер закончился), и поэтому передача управления не может произойти.

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

Лексическое связывание является режимом связывания по умолчанию для переменных Common Lisp. Для отдельного символа его можно переключить в динамическую область видимости либо локальным объявлением, либо глобальным объявлением. Последнее может происходить неявно посредством использования таких конструкций, как DEFVAR или DEFPARAMETER. Важным условием программирования на Common Lisp является то, что специальные (т.е. динамически ограниченные) переменные имеют имена, которые начинаются и заканчиваются звездочкой сигилом *в так называемом «соглашении наушников ». При соблюдении этого соглашения создается отдельное пространство имен для специальных переменных, так что переменные, которые должны быть лексическими, не могут быть случайно сделаны специальными.

Лексическая область полезна по нескольким причинам.

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

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

Третьи, возможно, наиболее важные, даже если лексические замыкания не используются, использование лексической области видимости изолирует программные модули от нежелательных взаимодействий. Из-за ограниченной видимости лексические переменные закрытые. Если один модуль A связывает лексическую переменную X и другой модуль B, ссылки на X в B не будут случайно разрешаться в X, привязанный к A. B просто не имеет доступа к X. В ситуациях, когда дисциплинированные взаимодействия через переменную являются желательно, Common Лисп специальный переменные. Специальные переменные позволяют модулю установить привязку для альтернативного X, которая видна другому модулю B, вызываемому из A. Возможность сделать это также является преимуществом; Следовательно, Common Lisp поддерживает как лексическую, так и динамическую область видимости.

Макросы

A макрос в Лиспе внешне напоминает функцию в использовании. Однако вместо того, чтобы представить вычисляемое выражение, оно представляет преобразование исходного кода программы. Макрос получает источник в качестве аргументов, привязывает их к своим параметрам и вычисляет новую формулу. Эта новая форма также может использовать макрос. Расширение макроса повторяется до тех пор, пока новая исходная форма не перестанет использовать макрос. Окончательная расчетная форма - это исходный код, выполняемый во время выполнения.

Тип использования макросов в Лиспе:

  • новые управляющие структуры (примеры: циклические конструкции, разветвленные конструкции)
  • конструкции области видимости и привязки
  • упрощенный синтаксис для сложного и повторяющегося исходного кода
  • определяющие формы верхнего уровня с побочными эффектами времени компиляции
  • программирование, управляемые данные
  • встроенные предметно-ориентированные языки (примеры: SQL, HTML, Prolog)
  • неявные формы завершения

Различные стандартные Common Lisp также должны быть реализованы в виде макросов, как:

  • стандартная абстракция setf, позволяющая настраивать функции расширения во время компиляции операторов присваивания / доступа <таких 633>с-аксессуарами, с-слотами, с-открытым файломи другими подобными Смакросами
  • В зависимости от реализации, ifили condявляется макросом, построенным на прочее, специальный оператор; , когдаи , еслине состоит из макросов
  • Мощный цикл циклпредметно-зависимый язык

Макросы макросом defmacro. Специальный макрос позволяет определять локальные макросы (с лексической областью видимости). Также можно определить макросы для символов с помощью define-symbol-macro и symbol-macrolet.

Книга Пола Грэма О Лиспе подробно использование макросов в Common Lisp. Книга расширяет обсуждение макросов, утверждая, что «макросы - это единственное самое большое преимущество, которое у Lisp как языка программирования, и самое большое преимущество любого языка программирования». Хойт приводит несколько примеров итеративной разработки макросов.

Пример использования макроса для определения новой структуры управления

Макросы позволяют программистам на Лиспе создать новые синтаксические формы на языке. Типичное использование - создание новых структур управления. В примере использования конструкции цикла от до. Синтаксис:

(до тестовой формы *)

Определение макроса для до:

(defmacro до (тест и тело тела) (let ((start-tag (gensym "START")) (end- tag ( gensym "КОНЕЦ"))) `(tagbody, start-tag (when, test (go, end-tag)) (progn, @ body) (go, start-tag), end-tag)))

tagbody - это примитивный специальный оператор Common Lisp, который дает возможность присваивать имена тегам и использовать форму перехода к этому тегам. Обратная кавычка `представляет собой нотацию, которая предоставляет шаблоны кода, где значения форм, предшествует запятая, заполняются. Формы, которым предшествует запятая и знак, соединяются. Форма tagbody проверяет конечное условие. Если условие истинно, выполнен переход к конечному тегу. В случае неисправного основного кода, выполняется переход к начальному тегу.

Пример использования указанного макроса до:

(до (= (random 10) 0) (строка записи «Hello»))

Код может быть расширен с помощью функций macroexpand- 1. Расширение для приведенного выше пример выглядит так:

(TAGBODY #: START1136 (WHEN (ZEROP (RANDOM 10)) (GO #: END1137)) (PROGN ( WRITE-LINE "привет")) (GO #: START1136) #: END1137)

Во время раскрытия макроса значение теста равно (= (random 10) 0), значение тела переменной - ((строка записи "Hello")). Тело - это список форм.

Символы обычно автоматически повышаются. Расширение использует TAGBODY с двумя метками. Символы для этих этикеток вычисляются GENSYM и не интернированы ни в какой пакет. Две формы идут использовать эти теги для перехода. Tagbody - это примитивный оператор в Common Lisp (а не макрос), он не будет расширен во что-то еще. В развернутой форме используется макрос, когда, который также будет внутри. Полное раскрытие исходной формы называется кодом кода.

В полностью развернутой (пройденной) форме форма, когда заменяется примитивом, если:

(TAGBODY #: START1136 (IF (ZEROP (RANDOM 10)) (PROGN (GO #: END1137)) NIL) (PROGN ( НАПИШИТЕ «привет»)) (GO #: START1136)) #: END1137)

Все макросы должны быть раскрыты, прежде чем исходный код, обеспечить их, можно будет оценить или скомпилировать в обычном режиме. Макросы можно рассматривать как функции, которые принимают и возвращают S-выражения - аналогично абстрактным синтаксическим деревьям, но не ограничиваются ими. Эти функции вызываются перед оценщиком или компилятором для создания окончательного исходного кода. Макросы написаны на обычном Common Lisp и могут использовать любой доступный Common Lisp (или сторонний) оператор.

Захват и затенение чисел

Макросы Common Lisp способны к так называемому использованию чисел, когда символы в теле расширения макроса совпадают с разными символами в вызывающем контексте, что позволяет программисту создать макросы, в которых используются символы особое значение. Термин «блокирование» несколько вводит в заблуждение, потому что все пространства имен уязвимы для нежелательного пространства захвата, включая имен оператора и функции, пространство метки tagbody, тег catch, обработчик условий и имен пространства перезапуска.

Захват может привести к дефектам программного обеспечения. Это происходит одним из следующих способов:

  • В первом случае расширение макроса может непреднамеренно создать символическую ссылку, как предполагал создатель макроса, разрешит в глобальном пространстве имен, но код, в котором раскрывается макрос, используется локальное теневое определение, которое крадет эту ссылку. Назовем это захватом типа 1.
  • Второй способ, захват типа 2, прямо противоположен: некоторые аргументы макроса предоставляют собой фрагменты кода, предоставленные вызывающим макросом, и эти фрагменты кодантом написан так, что он указан на окружающие привязки. Однако макрос вставляет эти фрагменты кода в расширение, которое определяет свои собственные привязки, которые случайно захватывают некоторые из этих ссылок.

Схема диалект системы в Lisp обеспечивает запись макросов, которая обеспечивает ссылочную прозрачность, исключающую оба типа захвата. проблема. Этот тип макросистемы иногда называют «гигиеничным», в частности, его сторонники (которые автоматически не решают эту проблему, негигиеничными).

В Common Lisp макросистема обеспечивается одним из двух различных путей.

Один из подходов заключается в использовании: гарантированно уникальных символов, которые находятся в макрорасширении без угрозы захвата. Использование генсимов в макросе - это ручная работа, но можно написать макросы, которые упростят создание и использование генсимов. Генсимы легко решают захват типа 2, но они не применимы к захвату типа 1 таким же образом, потому что расширение макроса не может переименовать мешающие символы в окружающем коде, которые захватывают его ссылки. Gensyms можно использовать для стабильных псевдонимов для глобальных символов, которые необходимы для макрорасширения. Расширение макроса будет использовать эти секретные псевдонимы, а не хорошо известные имена, поэтому переопределение хорошо известных имен не использует вредного воздействия на макрос.

Другой подход - использовать пакеты. Макрос, специфика в собственном пакете, может просто использовать внутренние символы этого пакета в своем расширении. Использование пакетов касается захвата типа 1 и типа 2.

Однако пакеты не решают проблему захвата типа 1 ссылок на стандартные функции и операторы Common Lisp. Причина в том, что использование пакетов для решения проблем захвата вращается вокруг обычных частных символов (символов в одном пакете, которые не становятся видимыми в других пакетах). В то время как символы библиотеки Common Lisp являются внешними и часто импортируются или становятся видимыми в пользовательских пакетах.

Ниже представлен пример рекомендательного захвата в имен операторов, происходящего при раскрытии макроса:

;; расширение UNTIL позволяет свободно использовать DO (defmacro until (expression body body) `(do () (, expression), @ body)) ;; macrolet устанавливает привязку лексического оператора для DO (macrolet ((do (...)... something else...)) (until (= (random 10) 0) (write-line "Hello")))

Макрос от дораскроется в формулу, которая вызывает do, которая предназначена для ссылок на стандартный макрос Common Lisp do. Однако в этом контексте doможет иметь совершенно другое значение, поэтому доможет работать неправильно.

Common Lisp решает проблему дублирования стандартных операторов и функций, запрещая их переопределение. Он может быть переопределяет стандартный оператор do, предыдущий фактически является фрагментом несоответствующего Common Lisp, что позволяет реализовать диагностировать и отклонить его.

Система условий

Система условий отвечает за обработка исключений в Common Lisp. Он предоставляет условия, обработчики и перезапуски. Условия - это объекты, описывающие исключительную ситуацию (например, ошибку). Если указано условие, система Common Lisp ищет обработчик для этого типа условия и вызывает обработчик. Теперь обработчик может искать перезапуски и использовать один из этих перезапусков для устранения текущей проблемы, используя такую ​​информацию, как типовые условия и любую соответствующую информацию, предоставленную как часть условий объекта, и вызвать соответствующую функцию перезапуска.

Эти перезапуски, если они не обрабатываются кодом, могут быть представлены пользователям (как часть пользовательского интерфейса, например, отладчика), чтобы пользователь мог выбрать и вызвать один из доступных перезапусков. Обработчик условий вызывается в контексте (без раскрутки стека), полное восстановление после ошибки во многих случаях, когда другие системы обработки исключений уже завершили бы текущую систему. Сам отладчик также можно настроить или заменить с помощью динамической модели * крючок-отладчик *. Код, найденный в формах защиты от размотки, таких как финализаторы, также будет надлежащим образом, несмотря на исключение.

В следующем примере (с использованием Symbolics Genera ) пользователь пытается открыть файл в функциональном тесте Lisp, вызываемый из Read-Eval-Print-LOOP (REPL ), когда файл не существует. Система Lisp предлагает четыре перезапуска. Пользователь выбирает Retry OPEN, используя перезапуск с другим именем пути, и вводит другое имя пути (lispm-init.lisp вместо lispm-int.lisp). Код пользователя не содержит кода обработки ошибок. Весь код обработки ошибок и перезапуска обеспечивается системой Lisp, которая может обрабатывать и исправлять ошибку, не прерывая пользовательский код.

Команда: (test ">zippy>lispm-int.lisp") Ошибка: файл не найден. Для lispm:>zippy>lispm-int.lisp.newest LMFS: OPEN-LOCAL-LMFS-1 Arg 0: #P "lispm:>zippy>lispm-int.lisp.newest" sA, : повторить попытку ОТКРЫТЬ из lispm:>zippy>lispm-int.lisp.newest sB: повторить попытку OPEN, используя другой путь sC, : вернуться на верхний Lisp на сервере TELNET sD: перезапустить процесс Терминал TELNET ->повторить попытку OPEN, используя другое имя пути Использовать какой путь вместо этого [по умолчанию lispm:>zippy>lispm-int.lisp.newest]: lispm:>zippy>lispm-init.lisp.newest... программа продолжается

Common Lisp Object System (CLOS)

Common Lisp включает набор инструментов для объектно-ориентированного программирования, объектной системы Common Lisp или CLOS, которая является одной из самых мощных объектных систем, доступных на любом языке. Например, Питер Норвиг объясняет, сколько шаблонов проектирования Проще реализовать на своем языке функции CLOS (динамическое наследование, миксины, мультиметоды, метаклассы, комбинации методов и т. Д.). Было предложено включить несколько расширений Common Lisp для объектно-ориентированного программирования в стандартном ANSI Common Lisp, но в итоге CLOS была принята как стандартная объектная система для Common Lisp. CLOS - это динамическая объектная система с множественной отправкой и множественным наследованием, которая радикально отличается от возможностей ООП, других в статических языках, таких как C + + или Java. Как динамическая объектная система, CLOS позволяет улучшить во время выполнения общие функции и классы. Можно добавить методы, можно изменить классы, можно обновлять объекты для изменений класса и можно изменить класс объектов.

CLOS интегрирован в ANSI Common Lisp. Общие функции как Мои функции и другие функции первоклассный тип данных. Каждый класс CLOS интегрирован в систему типов Common Lisp. Многие типы Common Lisp имеют соответствующий класс. Для Common Lisp существует больше возможностей использовать CLOS. В спецификации не говорится, реализуются ли условия с помощью CLOS. Пути и потоки могут быть реализованы с помощью CLOS. Эти дополнительные возможности использования CLOS для ANSI Common Lisp не являются стандартом. Фактические реализации Common Lisp используют CLOS для имен путей, потоков, ввода-вывода, условий, самого реализации CLOS и многого другого.

Компилятор и интерпретатор

Интерпретатор без ограничений исходный код Лиспа, предоставленные объекты Лиспа (списки, символы, числа,...), считанные из s-выражений. Компилятор Lisp генерирует байт-код или машинный код из исходного кода Lisp. Common Lisp позволяет компилировать как отдельные функции Lisp в память, так и компилировать целые файлы во внешне сохраненный скомпилированный код (файлы fasl).

Несколько реализаций ранних диалектов Лиспа, предоставляющих как интерпретатор, так и компилятор. К сожалению, часто семантика была иной. Эти более ранние Лиспы реализовали лексическую область видимости в компиляторе и динамическую область видимости в интерпретаторе. Common Lisp требует, чтобы и интерпретатор по умолчанию использовал лексическую область видимости. Стандарт Common Lisp присутствует семантику интерпретатора и компилятора. Компилятор может быть вызван использованием функций компиляции для отдельных функций и с использованием компиляции функций для файлов. Common Lisp позволяет типам объявления и способам влиять на политику генерации компилятора. Для последних различных качеств оптимизации могут быть заданы значения от 0 (не важно) до 3 (наиболее важно): скорость, пространство, безопасность, отладка и скорость компиляции.

Также существует функция для оценки кода Lisp: eval. evalпринимает код как проанализированные s-выражения, а не, как на некоторых других языках, как текстовые строки. Таким образом, код может быть построен с помощью обычных функций Лиспа для построения списков и символов, а затем этот код может быть оценен с помощью функций eval. Некоторые реализации Common Lisp (например, Clozure CL и SBCL) реализуют evalс помощью своего компилятора. Таким образом код компилируется, даже если он оценивается с помощью функции eval.

. Компилятор файла вызывается с помощью функции compile-file. Сгенерированный файл со скомпилированным кодом называется fasl (из быстрой быстрой). Эти файлы fasl, а также файлы исходного кода могут быть загружены с функцией загрузки работающей системы Common Lisp. В от реализации компилятора файла генерирует байт-код (например, для данной машины Java ), код языка C (который компилируется компилятором C) или напрямую, собственный код.

Реализации Common Lisp Program в интерактивном режиме, даже если код полностью компилируется. Таким образом, идея интерпретируемого языка неприменима к интерактивному Common Lisp.

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

Некоторые специальные операторы специально предназначены для интерактивной разработки; например, defvarприсваивает значение предоставленной стандартной только в том случае, если она еще не привязана, тогда как defparameterвсегда будет выполнять присвоение. Это полезно при интерактивной оценке, компиляции и загрузке кода в живом изображении.

Некоторые функции также выплаты для помощи в написании компиляторов и интерпретаторов. Символы состоят из объектов первого уровня и напрямую управляются пользовательским кодом. Специальный оператор progvпозволяет программно создавать лексические привязки, при этом пакетами также можно управлять. Компилятор Lisp доступен во время выполнения для компиляции файлов или отдельных функций. Это упрощает использование Lisp в качестве промежуточного компилятора или интерпретатора для другого языка.

Примеры кода

Парадокс дня рождения

Следующая программа вычисляет наименьшее количество людей в комнате, для которых вероятность уникальных дней рождения составляет менее 50% (парадокс дня рождения, где для 1 человека вероятность очевидно 100%, для 2 - 364/365 и т. д.). Ответ: 23.

По соглашению, константы в Common Lisp заключаются в символы +.

(defconstant + year-size + 365) (defun birthday-paradox (вероятность-число-людей) (let ((новая-вероятность (* (/ (- + размер года + количество людей) + год- size +) вероятность))) (if (< new-probability 0.5) (1+ number-of-people) (birthday-paradox new-probability (1+ number-of-people)))))

Вызов функции-примера с использованием REPL (Read Eval Print Loop):

CL-USER>(birthday-paradox 1.0 1) 23

Сортировка списка объектов person

Мы определяем класс personи метод для отображения имени и возраста человека. Затем мы определяем группу лиц как список объекты person. Затем мы перебираем отсортированный список.

(defclass person () ((name: initarg: name: accessor person-name) (age: initarg: age: accessor person-age)) (: документация «Класс PERSON со слотами NAME и AGE.»)) (defmethod display ((object person) stream) «Отображение объекта PERSON в потоке вывода.» (with-slots (name age) object (format stream) ~ a (~ a) "имя возраст))) (defparameter * group * (list (make-instance 'person: name" Bob ": age 33) (make-instance' person: name" Chr is " : age 16) (make-instance 'person: name "Ash": age 23)) "Список объектов PERSON.") (dolist (person (sort (copy-list * group *) #'>: key # ' person-age)) (display person * standard-output *) (terpri))

Он печатает три имени в порядке убывания возраста.

Боб (33) Эш (23) Крис (16)

Возведение в степень возведением в квадрат

Демонстрация использования макроса LOOP:

(defun power (xn) (цикл с результатом = 1 while (plusp n) when (oddp n) do (setf result (* result x)) do (setf x (* xx) n (truncate n 2)) finally (return result)))

Пример использования:

CL-USER>(мощность 2 200) 1606938044258990275541962092341162602522202993782792835301376

Сравните со встроенным возведением в степень:

CL-USER>(= (expt 2 200) (power 2 200)) T

Найдите список доступных shells

WITH-OPEN-FILE - это макрос, который открывает файл и предоставляет поток. Когда форма возвращается, файл автоматически закрывается. FUNCALL вызывает объект функции. LOOP собирает все строки, соответствующие предикату.

(defun list-matching-lines (предикат файла) «Возвращает список строк в файле, для которых примененный к строке предикат возвращает T.» (with-open-file (файл потока) (цикл для строки = (read-line stream nil nil) while line when (funcall predicate line) собирает его)))

Функция AVAILABLE-SHELLS вызывает вышеупомянутую функцию LIST-MATCHING-LINES с именем пути и анонимной функцией в качестве предиката. Предикат возвращает путь к оболочке или NIL (если строка не является именем файла оболочки).

(defun available-shells (optional (file #p "/ etc / shells")) (файл списка совпадающих строк (lambda (line) (and (plusp (length line)) (char = (char line 0) # \ /) (pathname (string-right-trim '(# \ space # \ tab) line))))))

Пример результатов (в Mac OS X 10.6):

CL-USER>( доступные оболочки) (#P "/ bin / bash" #P / bin / csh "#P" / bin / ksh "#P" / bin / sh "#P" / bin / tcsh "#P" / bin / zsh ")

Сравнение с другими Lisp

Common Lisp наиболее часто сравнивается и противопоставляется Scheme - хотя бы потому, что это два самых популярных диалекта Lisp. Scheme предшествует CL и исходит не только из той же традиции Lisp, но и от некоторых из тех же инженеров - Гая Л. Стила, с которым Джеральд Джей Сассман разработал Scheme, председатель комитета по стандартам для Common Lisp.

Common Lisp - это язык программирования общего назначения, в отличие от вариантов Lisp, таких как Emacs Lisp и AutoLISP, которы е являются встроенными языками расширения в конкретных продуктах (GNU Emacs и AutoCAD соответственно). В отличие от многих более ранних Лиспов, Common Lisp (например, Scheme ) по умолчанию использует лексическую переменную scope как для интерпретируемого, так и для скомпилированного кода.

Большинство систем Лиспа, чьи конструкции способствовали развитию Common Lisp, такие как ZetaLisp и Franz Lisp, использовали переменные с динамической областью действия в своих интерпретаторах и переменные с лексической областью видимости в своих интерпретаторах. компиляторы. Scheme ввел в Lisp единственное использование переменных с лексической областью видимости; вдохновение из АЛГОЛА 68. CL также поддерживает переменные с динамической областью видимости, но они должны быть явно объявлены как «специальные». Нет различий в области видимости между интерпретаторами и компиляторами ANSI CL.

Common Lisp иногда называют Lisp-2, а Scheme - Lisp-1, имея в виду использование CL отдельных пространств имен для функций и переменных. (Фактически, CL имеет много пространств имен, например, для тегов go, имен блоков и ключевых слов loop). Между сторонниками CL и Scheme существует давняя полемика по поводу компромиссов, связанных с несколькими пространствами имен. В Scheme (в широком смысле) необходимо избегать указания имен переменных, которые конфликтуют с функциями; Функции схемы часто имеют аргументы с именами lis, lstили lyst, чтобы не конфликтовать с системной функцией list. Однако в CL необходимо явно ссылаться на пространство имен функции при передаче функции в качестве аргумента - что также является обычным явлением, как в примере sortвыше.

CL также отличается от Scheme обработкой логических значений. Схема использует специальные значения #t и #f для представления истины и лжи. CL следует старому соглашению Lisp об использовании символов T и NIL, причем NIL также обозначает пустой список. В CL любое значение, отличное от NIL, трактуется как истинное условными операторами, такими как if, тогда как в схеме все значения, отличные от # f, обрабатываются как истинные. Эти соглашения позволяют некоторым операторам на обоих языках служить как предикатами (отвечая на вопрос с логическим значением), так и возвращать полезное значение для дальнейшихвычислений, но в Scheme значение '(), которое эквивалентно NIL в Common Lisp, оценивается как истинное. в логическом выражении.

И, наконец, документы стандартов Схема требует оптимизации хвостового вызова, чего не требует стандарт CL. Большинство реализаций CL выполняет оптимизацию хвостового вызова, когда программист использует директиву оптимизации. Тем не менее, общий стиль кодирования CL не способствует повсеместному использованию рекурсии, которую предпочитает Схема - то, что программист Схема выразил бы хвостовой рекурсией, пользователь CL обычно выражает итеративным выражением в do, dolist, loopили (совсем недавно) с пакетом итерация.

Реализации

См. Категорию Реализации Common Lisp.

Common Lisp определяется спецификацией (например, Ada и C ) без одной реализации (например, Perl ). Существуют различные реализаций и стандартные детали, в которых они действительно различаться.

Кроме того, реализация, как правило, поставляется с расширениями, которые обеспечивают функциональность, не охваченную стандартом:

  • Интерактивный верхний уровень (REPL)
  • Сборка мусора
  • Отладчик, Stepper и Inspector
  • Слабые структуры данных (хеш-таблицы)
  • Расширяемые следящие
  • Extensible LOOP
  • Доступ к среде
  • CLOS Мета-протокол объекта
  • Расширяемый потоки на основе CLOS
  • Система условий на основе CLOS
  • Сетевые потоки
  • Постоянный потоки на основе CLOS
  • Поддержка Unicode
  • Интерфейс на иностранном языке (часто на C)
  • Интерфейс операционной системы
  • Интерфейс Java
  • Потоки и многопроцессорность
  • Доставка приложений ( приложения, динамические библиотеки)
  • Сохранение изображений

Бесплатное программное обеспечение с открытым исходным кодом библиотеки были созданы для поддержки расширений Common Lisp переносимым способом, и в основном они находятся в ре позиториях Common-Lisp.net и CLOCC (Common Lisp Open Code Collection) проекты.

Реализации Common Lisp могут использовать любое сочетание компиляции собственного кода, компиляции или интерпретации байтового кода. Common Lisp разработан для поддержки инкрементных компиляторов, компиляторов файлов и блочных компиляторов. Стандартные объявления для оптимизации компиляции (например, встраивание функций или специализация типов) Указ в спецификации языка. Большинство реализаций Common Lisp компилируют исходный код в машинный код . Некоторые реализации могут создать (оптимизированные) автономные приложения. Другие компилируют в интерпретируемый байт-код , который менее эффективен, чем собственный код, но облегчает перенос двоичного кода. Некоторые компиляторы компилируют код Common Lisp в код C. Ошибочное представление о том, что Lisp является чисто интерпретируемым языком, скорее всего, связано с тем, что среда Lisp предоставляет интерактивные подсказки и этот код компилируется один за другим, поэтапно. В Common Lisp широко используется инкрементная компиляция.

Некоторые реализации на основе Unix (CLISP, SBCL ), как язык сценариев ; то есть вызывается системой прозрачно, как интерпретатор Perl или оболочки Unix.

Список реализаций

Коммерческие реализации

Allegro Common Lisp
для Microsoft Windows, Macintosh, Linux, AppleOS и различных вариантов UNIX. Allegro CL предоставляет интегрированную среду разработки (IDE) (для Windows и Linux) и обширные возможности для доставки приложений.
ранее назывался Lucid Common Lisp. Только обслуживание, никаких новых выпусков.
LispWorks
для Microsoft Windows, FreeBSD, Linux, Apple macOS, iOS, Android и различных вариантов UNIX. LispWorks предоставляет интегрированную среду разработки (IDE) (доступную для всех платформ, но не для iOS и Android) и обширные возможности для доставки приложений.
mocl
для iOS, Android и macOS.
Open Genera
для DEC Alpha.
который разработан для высокопроизводительных научных вычислений.

свободно распространяемые реализации

Armed Bear Common Lisp (ABCL)
реализация CL, которая работает на данную машину Java. Он включает компилятор для байтового кода Java и обеспечивает доступ к библиотеке Java из CL. Раньше он был просто компонентом.
CLISP
Реализация компиляции байт-кода, переносимая и работающая в нескольких Unix и Unix-подобных системах (включая macOS ), а также в Microsoft Windows и нескольких других системах.
Clozure CL (CCL)
Первоначально бесплатная ветвь Macintosh Common Lisp с открытым исходным кодом. Как следует из этой истории, CCL был написан для Macintosh, но Clozure CL теперь работает на macOS, FreeBSD, Linux, Solaris и Windows. 32- и 64-битные порты x86 поддерживаются на каждой платформе. Дополнительно есть порты Power PC для Mac OS и Linux. CCL ранее известен как OpenMCL, но это имя больше не используется, чтобы избежать путаницы с версией Macintosh Common Lisp с открытым исходным кодом.
CMUCL
Первоначально из Университета Карнеги-Меллона, теперь поддерживается как бесплатное программное обеспечение с открытым исходным кодом от группы добровольцев. CMUC использует быстрый компилятор машинного кода. Он доступен в Linux и BSD для Intel x86; Linux для Alpha; macOS для Intel x86 и PowerPC; и Solaris, IRIX и HP-UX на их собственных платформах.
Corman Common Lisp
для Microsoft Windows. В январе 2015 года Корман Лисп был опубликован под лицензией MIT.
Встраиваемый Common Lisp (ECL)
ECL включает интерпретатор и компилятор байт-кода. Он также может компилировать код Lisp в машинный код через компилятор C. Затем ECL компилирует код Lisp в C, компилирует код C с помощью компилятора C и затем может загрузить полученный машинный код. Также можно встраивать ECL в программы C, а код C - в программы Common Lisp.
GNU Common Lisp (GCL)
GNU Компилятор проекта Lisp. Еще не полностью совместимый с ANSI, GCL, тем не менее, предпочтительная реализация математической реализации для нескольких проектов, включая инструменты Maxima, AXIOM и (исторически) ACL2. GCL работает в Linux под одиннадцатью различными архитектурами, а также в Windows, Solaris и FreeBSD.
Macintosh Common Lisp (MCL)
Версия 5.2 для компьютеров Apple Macintosh с процессором PowerPC под управлением Mac OS X имеют открытый исходный код. RMCL (на основе MCL 5.2) работает на компьютерах Apple Macintosh на базе Intel с использованием двоичного транслятора Rosetta от Apple.
(MKCL)
Ответвление ECL. MKCL подчеркивает надежность, стабильность и общее качество кода за счет сильно переработанной, изначально многопоточной системы времени выполнения. В Linux MKCL имеет полностью совместимую с POSIX времени выполнения.
Реализует среду Lisp для компьютеров x86, не полагаясь на какую-либо базовую ОС.
Poplog
Poplog реализует версию CL с POP-11 и, возможно, Prolog и Standard ML (SML), позволяющие программировать на разных языках. Для всех реализаций POP-11, который компилируется постепенно. Он также имеет встроенный Emacs -подобный редактор, который взаимодействует с компилятором.
Steel Bank Common Lisp (SBCL)
Ответвление от CMUCL. «Вообще говоря, SBCL отличается от CMU CL большим упором на ремонтопригодность». SBCL работает на платформех CMUCL, кроме HP / UX; кроме того, он работает в Linux для AMD64, PowerPC, SPARC, MIPS, Windows x86 и имеет экспериментальную поддержку для работы в Windows AMD64. SBCL по умолчанию не использует интерпретатор; все выражения компилируются в машинный код, если пользователь не включает интерпретатор. Компилятор SBCL генерирует быстрый машинный код в соответствии с предыдущей версией The Computer Language Benchmarks Game.
порта CLISP для платформы Windows с ядром, написанным на C ++.

Другие реализации

Austin Kyoto Common Lisp
развитие Kyoto Common Lisp от Билла Шелтера
Butterfly Common Lisp
реализация, написанная на Схема для BBN Butterfly мультипроцессорный компьютер
CLICC
компилятор Common Lisp to C
CLOE
Common Lisp для ПК от Symbolics
Codemist Common Lisp
используется для коммерческой версии системы компьютерной алгебры Axiom
ExperCommon Lisp
ранняя реализация для Apple Macintosh от ExperTelligence
реализация для ПК от GoldHill Inc.
Ibuki Common Lisp
коммерческая версия Kyoto Common Lisp
Kyoto Common Lisp
первого компилятора Common Lisp, который использовал C в качестве целевого языка. GCL, ECL и MKCL происходят от этой реализации Common Lisp.
L
небольшая версия Common Lisp для встроенных систем, разработанная IS Robotics, теперь iRobot
Машины Лиспа (от Symbolics, TI и Xerox)
предоставляли реализацию Common Lisp в дополнение к их родному диалекту Лиспа (Lisp Machine Lisp или Interlisp). Также был доступен CLOS. Symbolics предоставляет расширенную версию Common Lisp.
Procyon Common Lisp
реализация для Windows и Mac OS, используемая Franz для их Windows-порта Allegro CL
Star Sapphire Common LISP
реализация для ПК
SubL
Common Lisp, для использования реализации Cyc системы, основанной на знаниях
Common Lisp верхнего уровня
ранняя реализация для параллельного выполнения
WCL
реализация разделяемой библиотеки
Vax Common Lisp
реализация Digital Equipment Corporation, которая выполнялась в системах VAX, работающих под управлением VMS или ULTRIX
XLISP
реализация, написанная Дэвидом Бетцем

Приложения

Common Lisp для разработки исследовательских приложений, для быстрой разработки прототипов или для развернутых приложений.

Common Lisp используется во многих коммерческих приложениях, включая сайт веб-коммерции Yahoo! Магазин, в котором изначально участвовал Пол Грэм, а позже был переписан на C ++ и Perl.. Другие примечательные примеры включают:

  • ACT-R, когнитивную программууру, используемую в большом количестве исследовательских проектов.
  • Помощник авторизатора, большая основанная на правилах система, используемая American Express для анализа кредитных запросов..
  • Cyc, длительный проект по созданию системы основанной на знаниях, который обеспечивает объем здравого смысла
  • , экспертную систему в реальном времени и механизм бизнес-правил
  • Genworks GDL на основе ядра Gendl с открытым исходным кодом.
  • Среда разработки для серии видеоигр Jak and Daxter, разработанная Naughty Dog.
  • Поисковая система по низким тарифам ITA Software, используемые туристическими сайтами, такими как Orbitz и Kayak.com, и такими компаниями, как American Airlines, Continental Airlines и US Airways.
  • Mirai, пакет трехмерной графики. Он использовался для анимации лица Голлума в фильме «Властелин колец: Две башни».
  • Система проверки прототипов (PVS), механизированная среда для формальной спецификации и проверки.
  • PWGL представляет собой сложную среду визуального программирования, основанную на Common Lisp, используемую в Компоновка с помощью компьютера и синтез звука.
  • Piano, полный пакет анализа самолетов такими, написанными на Common Lisp, используя компанию, как Boeing, Airbus, Northrop Grumman.
  • Grammarly, русскоязычная платформа для улучшения письма, ядро ​​грамматического движка которой написано на Common Lisp
  • Инструмент динамического анализа и перепланирования (DART), который, как говорят, один окупил с 1991 по 1995 все тридцать лет инвестиций DARPA в исследования ИИ.
  • «Удаленный агент » НАСА (Лаборатория реактивного движения), отмеченная наградами программа Common Lisp для автопилотирования космического корабля Deep Space One.
  • SigLab, Co Платформа mmon Lisp для обработки сигналов используемой в противоракетной обороне, построенная Raytheon
  • Система планирования миссии NASA Mars Pathfinder
  • SPIKE, система планирования для наземных или космических обсерваторий и спутников, особенно Hubble Space Telescope., написанный на Common Lisp
  • Common Lisp был использован для прототипа сборщика мусора Microsoft.NET Common Language Runtime
  • Исходная версия Reddit, хотя позже разработчики перешли на Python из-за отсутствия библиотек для Common Lisp, согласно официальному сообщению в блоге соучредителя Reddit Стива Хаффмана.

Также существуют открытые - исходные приложения, написанные на Common Lisp, такие как:

См. также

  • значок Портал компьютерного программирования

Ссылки

Библиография

Хронологический список опубликованных (или готовящихся к публикации) книг о Common Lisp (языке) или о программировании на Common Lisp (особенно программировании AI).

Внешние ссылки

Викиучебники содержат больше информации по теме: Common Lisp
Последняя правка сделана 2021-05-15 07:10:31
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте