[Перевод] Что сделало Lisp особенным
»Величайший из когда-либо созданных языков программирования»
— Alan Kay, «on Lisp»
Когда Маккарти разработал Lisp в конце 1950-х, он радикально отличался от существующих языков, самым главным из которых был Fortran.
Lisp воплотил девять новых идей:
1. Условные высказывания (Conditionals). Условные высказывания это if-then-else конструкция. Сейчас мы воспринимаем их как должное. Они были изобретены Маккарти во время разработки Lisp. (Fortran в то время имел только goto-утверждения, тесно связанные с инструкцией ветвления на лежащем в основе железе.) Маккарти, будучи в комитете по Algol, внёс условия в Algol, откуда они распространились на другие языки.
2. Функциональные типы (A function type). В Lisp’е функции это объекты первого класса — они являются типом данных, также как числа, строки и т.д., и имеют буквальное представление, могут храниться в переменных, могут быть переданы как аргументы, и.т.д.
3. Рекурсия (Recursion). Рекурсия, конечно, существовала как математическая концепция до Lisp’а, но Lisp был первым языком программирования поддерживающим её. (Это возможно подразумевается в создании функций как объектов первого класса.)
4. Новая концепция переменных (A new concept of variables). В Lisp’е все переменные являются эффективными указателями. Значения — это то, что есть у типов, а не у переменных, а присвоение или связывание переменных означает копирование указателей, а не того, на что они указывают.
5. Сборка мусора (Garbage-collection).
6. Программы состоят из выражений (Programs composed of expressions). Программы на Lisp’е это деревья выражений, каждое из которых возвращает значение. (Некоторые Lisp-выражения могут возвращать множественные значения.) Это входит в контраст с Fortran’ом и с множеством других успешных языков, которые различают «выражения» и «утверждения».
Было естественным иметь такое различие в Fortran’е, потому что язык был линейно-ориентированным (не удивительно для языка, в котором форматом ввода была перфокарта). Вы не могли иметь вложенные утверждения. И пока вам требовались математические выражения для работы, не было смысла в том, чтобы заставлять что-нибудь ещё возвращать значение, потому что могло не быть чего-то, что ожидало возврата.
Ограничения были сняты с появлением блочно-структурированных языков, но к тому моменту было уже слишком поздно. Различие между выражениями и утверждениями уже закрепилось. Оно перешло от Fortran’а к Algol’у и далее к их потомкам.
Когда язык сделан полностью из выражений, вы можете составлять выражения как пожелаете. Вы можете написать либо (используя синтаксис Arc)
(if foo (= x 1) (= x 2))
либо
(= x (if foo 1 2))
7. Символьный тип (A symbol type). Символы отличаются от строк, в этом случае вы можете проверить на равенство, сравнив указатели.
8. Нотация для кода (A notation for code) с использованием деревьев из символов.
9. Весь язык всегда доступен (The whole language always available). Нет явного различия между временем чтения, временем компиляции и временем выполнения. Вы можете компилировать или запускать код во время чтения, или читать или запускать кода пока компилируете, или читать или компилировать код во время выполнения.
Запуск кода во время чтения позволяет пользователям перепрограммировать синтаксис Lisp’а; запуск кода во время компиляции это основа для макросов; компилирование во время выполнения это основа использования Lisp’ов как языка расширения в таких программах как Emacs; и наконец, чтение во время выполнения позволяет программам взаимодействовать, используя s-выражения, идея, недавно переизобретённая в XML.
Заключение
Когда Lisp был только изобретён, все эти идеи были сильно далеки от обычных практик программирования, которые диктовались железом, доступным в конце 1950-х.
Со временем язык по умолчанию, воплощённый в успехе популярных языков, постепенно эволюционировал в сторону Lisp. Пункты 1–5 теперь широко распространены. Пункт 6 начинает появляться в мэйнстриме. В Python’е в некотором виде есть пункт 7, хотя подходящего синтаксиса нет. Пункт 8, который (с пунктом 9) делает возможным макросы в Lisp’е, до сих пор есть только в Lisp’е, возможно потому что (а) он требует эти скобки или чего-то столь же плохого, и (б) если вы добавите это последнее увеличение мощности, то больше не сможете утверждать, что изобрели новый язык, а только лишь разработали новый диалект Lisp’а; -)
Хотя это полезно для современных программистов, странно описывать Lisp с точки зрения его отличия от случайных приёмов, принятых в других языках. Возможно это не то, о чём думал Маккарти. Lisp не был спроектирован, чтобы исправить ошибки Fortran’а; он появился скорее как побочный продукт попытки аксиоматизировать вычисления.