Common Lisp

(перенаправлено с «Common LISP»)

Common Lisp (сокращённо — CL) — диалект языка программирования Лисп, стандартизированный ANSI[1]. Был разработан с целью объединения разрозненных на момент начала 1980-х годов диалектов Лиспа; доступно несколько реализаций Common Lisp, как коммерческих, так и свободно распространяемых.

Common Lisp
Семантика мультипарадигмальный: объектно-ориентированный, функциональный, императивный, метаязык
Класс языка язык программирования, процедурный язык программирования, объектно-ориентированный язык программирования, язык функционального программирования и мультипарадигмальный язык программирования
Тип исполнения компилируемый
Появился в 1984, стандартизирован ANSI в 1994
Автор комитет X3J13
Разработчик X3J13[d]
Система типов сильная, динамическая, с опциональными декларациями типов
Основные реализации Allegro Common Lisp, ABCL, CLISP, Clozure CL, CMUCL, Corman Common Lisp, ECL, LispWorks, Scieneer CL, SBCL
Испытал влияние Lisp, Lisp Machine Lisp, MacLisp, InterLisp, Scheme
Повлиял на Clojure, Factor, Dylan, EuLisp, ISLisp, SKILL, Stella, SubL
Сайт common-lisp.net (англ.)
Логотип Викисклада Медиафайлы на Викискладе

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

История править

Работа над диалектом началась в 1981 году по предложению управляющего DARPA Боба Энгельмора.

Разработка координировалась посредством электронной почты, первоначальная структура языка существенно переработана по мере продвижения. Первый обзорный материал по разработке стандарта представлен Гаем Льюисом Стилом на Симпозиуме ACM по Лиспу и функциональному программированию в 1982 году, а первый документ по языку опубликован в 1984 году («Язык Common Lisp, первая редакция»). Вторая редакция, выпущенная в 1990 году, включала много изменений, произведённых ANSI над языком в процессе стандартизации. Конечную же редакцию стандарта опубликовали в 1994 году.

По состоянию на 2018 год никаких обновлений стандарта выпущено не было, а различные расширения и улучшения для Common Lisp (такие, как поддержка Юникода, параллелизм, основанные на CLOS ввод-вывод) обеспечиваются реализацией и библиотеками (многие доступны посредством Quicklisp).

Синтаксис править

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

(+ 2 2)                       ; складывает 2 и 2, возвращая результат 4. 
(- 8 3)                       ; вычитает из восьми три, возвращая результат 5. 
(reverse "Здравствуй, мир!")  ; переворачивает строку, возвращая «"!рим ,йувтсвардЗ"»

;; определения переменных и функций:
(defvar *x*)                  ; Определяет переменную *x*, не присваивая ей какого-либо
                              ; значения. Две звёздочки, являющиеся частью имени — принятый 
                              ; стандарт для именования глобальных переменных.

(setf *x* 42.1)               ; присваивает переменной *x* значение с плавающей запятой 42,1.

(defun square (x)             ; Определение функции square, получающей один аргумент
  (* x x))                    ; и возвращающей его квадрат.

(square *x*)                  ; вызывает функцию square, передавая ей значение переменной *x*
                              ; и возвращает её квадрат (1772,41).

(let ((a 3)(b 4)) (+ a b))    ; Специальная форма let создаёт локальные переменные, присваивает им значения
                              ; (в данном случае переменной a присваивается значение 3, а b - 4), 
                              ; после чего вычисляет и возвращает результат функции
                              ; (в данном случае 7). Переменные локальны, следовательно
                              ; попытка посчитать значение (+ a b) вне тела let приведёт к ошибке.

Типы данных править

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

Числовые типы включают в себя целые, дроби, числа с плавающей запятой и комплексные числа[2]. Common Lisp даёт возможность использовать большие числа для представления любых величин с большей точностью.

Литеры в Common Lisp не ограничены ASCII, большинство современных реализаций поддерживает Юникод.

Понятие символа, практически не используемое в таком виде в других языках — одно из ключевых, это уникальный объект из данных, включающих в себя: имя, значение, функцию, список свойств и пакет (пространство имён). Символы в Лиспе часто используются так же, как идентификаторы в других языках: для хранения значения переменной. Однако, у них есть множество других применений. Обычно, когда символу присваивается значение, оно тут же им и возвращается. Некоторые символы присваивают значение сами себе, так, например, булевы значения представлены в качестве двух самоопределяющихся символов, — T и NIL.

Есть несколько функций для округления скалярных типов разными способами. Функция round округляет аргумент до ближайшего целого числа, а если число стоит «посередине», то до ближайшего чётного. Функция truncate округляет числа по направлению к нулю. Функции floor и ceiling округляют к ближайшему меньшему и ближайшему большему числу соответственно. Все функции возвращают дробную часть в качестве вторичного результата.

Структуры данных править

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

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

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

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

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

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

Классы — часть объектной системы CLOS, — похожи на структуры, но они обеспечивают возможности множественного наследования и более динамического поведения. Классы были добавлены в Common Lisp поздно, и в чём-то концептуально перекрывают структуры. Объекты, созданные из классов, называются экземплярами. Особым случай являются обобщённые функции, являющиеся одновременно функциями и экземплярами.

Функции править

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

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

 ;; Сортирует список, используя функции > и <.
 (sort (list 5 2 6 3 1 4) #'>)   ; возвращает (6 5 4 3 2 1)
 (sort (list 5 2 6 3 1 4) #'<)   ; возвращает (1 2 3 4 5 6)
 ;; Сортирует список по первым элементам подсписков.
 (sort (list '(9 A) '(3 B) '(4 C)) #'< :key #'first)   ; возвращает ((3 B) (4 C) (9 A))

Определение функций править

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

 (defun square (x)
   (* x x))

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

 (defun square (x)
   "Calculates the square of the single-float x."
   (declare (single-float x) (optimize (speed 3) (debug 0) (safety 1)))
   (the single-float (* x x)))

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

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

 (flet ((square (x)
          (* x x)))
   (square 3))

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

Реализации править

Common Lisp отличается от таких языков, как C#, Java, Perl, Python тем, что он определяется своим стандартом и не существует его единственной или канонической реализации. Любой желающий может ознакомиться со стандартом и создать свою собственную реализацию. Common Lisp автоматически признаёт эти типы как равные.[3]

Таблица сравнения основных реализаций[4][5]
Название Поддерживаемые платформы Компиляция Возможности Лицензия
CLISP[6] Windows, Mac, *nix Байт-код, JIT Маленький размер образа лисп-системы. Очень эффективная длинная целочисленная арифметика. Возможность создания исполняемых файлов. FFI(интерфейс для вызова низкоуровневых функций(функций из библиотек, написанных на Си и т. п.) и для оперирования «неуправляемой» памятью). Функции обратного вызова(интеграция с «родным» кодом платформы). GNU GPL
CMUCL[7] Linux, FreeBSD, Solaris, Darwin Байт-код, машинный код Высококачественный компилятор в машинный код. FFI. Функции обратного вызова(интеграция с «родным» кодом платформы). Общественное достояние с частями под BSD License
ECL Windows, *nix, Mac OS X Байт-код, машинный код через Си Хорошая интеграция с программами на Си и с непосредственно исполняемым кодом платформы (FFI, функции обратного вызова, возможность создания бинарных динамических и статических библиотек). Возможность создания исполняемых файлов. Многопоточность на всех поддерживаемых платформах. GNU GPL с частями под другими лицензиями
Clozure CL (бывший OpenMCL)[8] Linux/PPC, Linux/X86-64, Darwin/PPC, Darwin/X86-64, FreeBSD/X86-64, Windows Машинный код Быстрый компилятор. Мощный и удобный FFI. Функции обратного вызова (интеграция с бинарным кодом платформы). Возможность создания исполняемых файлов. Многопоточность на всех поддерживаемых платформах. LGPL
SBCL[9] Linux, BSD, Solaris, Mac OS X (Darwin), Windows (экспериментально) Машинный код Развитый компилятор в машинный код. Возможность создания исполняемых файлов. FFI. Функции обратного вызова (интеграция с бинарным кодом платформы). Многопоточность на Linux, Solaris 10 и Mac OS X. Общественное достояние с частями под MIT License и BSD License
ABCL[10] JVM байт-код JVM Интерфейс к платформе Java. Многопоточность. Платформонезависимость. LGPL
Allegro Common Lisp[11] Windows, Unix, Linux, Mac OS X Машинный код Коммерческая, доступна ограниченная демоверсия
LispWorks[12] Windows, *nix, Mac OS X Машинный код Развитая IDE. CAPI — библиотека для создания пользовательского интерфейса. Хорошая интеграция с программами на Си и с «родным» кодом платформы (FFI, функции обратного вызова, возможность создания «родных» для платформы динамических и статических библиотек). Возможность создания исполняемых файлов. Многопоточность на всех поддерживаемых платформах. Коммерческая, доступна ограниченная демоверсия
Corman Common Lisp Windows Машинный код С 2015 года — MIT License. Изначально распространялся как Shareware, с доступным исходным кодом системы (исключая IDE)

Примечания править

  1. ANSI INCITS 226—1994 (R2004), ранее X3.226-1994 (R1999)
  2. Features of Common Lisp Архивировано 26 декабря 2009 года.
  3. Lisp — программируемый язык программирования. Дата обращения: 24 апреля 2010. Архивировано 12 сентября 2009 года.
  4. Список основных реализаций Common Lisp. Дата обращения: 15 мая 2007. Архивировано 1 мая 2007 года.
  5. Lisp Implementations Архивировано 4 июля 2008 года.
  6. [GNU CLISP (англ.). Дата обращения: 24 апреля 2010. Архивировано 16 марта 2010 года. GNU CLISP (англ.).]
  7. CMUCL. Дата обращения: 15 мая 2007. Архивировано 30 октября 2005 года.
  8. Clozure CL. Дата обращения: 10 июня 2008. Архивировано 5 марта 2018 года.
  9. [Steel Bank Common Lisp (англ.). Дата обращения: 24 апреля 2010. Архивировано 6 июня 2004 года. Steel Bank Common Lisp (англ.)]
  10. Armed Bear Common Lisp. Дата обращения: 10 июня 2008. Архивировано из оригинала 29 марта 2007 года.
  11. [Allegro CL — разработчик Franz Inc. (англ.). Дата обращения: 24 апреля 2010. Архивировано 18 июня 2020 года. Allegro CL — разработчик Franz Inc. (англ.)]
  12. LispWorks Архивная копия от 2 июня 2007 на Wayback Machine. Разработчик — LispWorks, LLC (ранее Xanalys, Inc.)

Ссылки править