Язык программирования лисп кратко

Обновлено: 04.07.2024

Оригинал: "Lisp: Tears of Joy, Part 1"
Автор: Vivek Shangari
Дата публикации: June 1, 2011
Перевод: Н.Ромоданов
Дата перевода: Август 2012 г.

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

"Я возненавижу свою работу", - это были мои первые мысли, когда я несколько лет назад получил назначение на работу. Мне дали задание по сопровождению и настройке клиентского модуля, написанного на языке Lisp. В моем восприятии язык Lisp был одним из древних функциональных языков программирования с загадочным синтаксисом, используемым только академиками и учеными для проведения экспериментов в области искусственного интеллекта. А количество скобок, вездесущих в Lisp-е, было достаточным, чтобы свести с ума любого!

В то время я считал, что я был асом в крутом современном объектно-ориентированном языке программирования, который был средством моего самовыражения: я ел, пил, спал и мечтал на этом языке. Он сделал меня Богом в моем компьютерном мирке. Я также верил, что я нравлюсь женщинам, проводил часы, приводя в порядок свою прическу, и вел свой старенький и потрепанный скутер Kinetic Honda точно так, как если бы это был крутейший спорт-байк 1340cc Suzuki Hayabusa.

Теперь я понимаю в этом больше .

Дежа вю

О тех из нас, кто был свидетелем перехода от парадигмы неструктурного программирования к процедурному программированию, а затем - к объектно-ориентированному программированию, скажут то, что Пол Грэм (Paul Graham) уже сказал в своей книге "Хакеры и художники" ("Hackers & Painters"). В частности: "То, что вы не можете доверять мнению других о языке программирования, делает вас лучшим программистом. Вам будет достаточно любого языка программирования, который вам придется пользоваться, поскольку язык будет определять, как вы будете обдумывать программы. Я знаю это из собственного опыта, поскольку в старших классах школы писал программы на языке BASIC. В этом языке не поддерживается даже рекурсия. Трудно представить, как писать программы без рекурсии, но в тот момент я этого не заметил. Я думал на языке BASIC. И в нем я был волшебником. Лучшим среди всех".

Три недели на изучение Lisp-а и у меня возникло ощущение дежа вю — так было раньше, когда я сначала "продвигался" от BASIC к С и от С к C++ и к Java. Тогда на каждом шаге я приятно удивлялся растущей мощью (программирования), оказавшейся в моих руках. Снова и снова я удивляюсь, как я кодировал без объектов, методов, инкапсуляции, полиморфизма, наследования и так далее! Можно сказать, что это синтаксические сладости моей работы.

Но не с Lisp-ом, который является чистым экстези. Он не только красивый, он - странно красивый.

В своем знаменитом эссе "Как стать хакером" ("How to become a Hacker") Эрик Стив Реймонд (Eric Steven Raymond), автор многих бестселлеров, в том числе бестселлера "Собор и базар" ("The Cathedral and the Bazaar"), пишет: "Обучение в Lisp-е состоит в получении практического опыта, которым вы будете обладать, когда вы его, наконец, освоите. Этот опыт, даже если вы больше никогда не будете пользоваться языком Lisp, сделает вас лучшим программистом на всю оставшуюся жизнь".

Lisp научит вас как специалиста

Так что же такого замечательного в Lisp? Как это он вас научит как специалиста? Специалист по Lisp-у Пол Грэм (Paul Graham) объясняет это так искусно и методически, что неуместно отвечать на этот вопрос по-иному. Пять языков (Python, Java, C/C++, Perl и Lisp), которые Эрик Рэймонд (Eric Raymond ) рекомендует осваивать специалистам, сильны каждый по-своему. В каких-то специальных вопросах, каждый из них может уступать другому, но, я думаю, что выше всех находится Lisp. И в пользу этого утверждения, я расскажу вам об одной из возможностей, которая, как я считаю, когда я смотрю на другие четыре языка, просто забыта. Что вы в них можете сделать без макросов?

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

Если вы разбираетесь в том, как работают компиляторы, вы поймете, что дело на самом деле не в том, что в Lisp используется странный синтаксис (везде круглые скобки!), а в том, что в нем нет синтаксиса (на самом деле синтаксис присутствуют в любом языке; в языке Lisp используется чрезвычайно простой и интуитивно понятный синтаксис с использованием круглых скобок — прим.пер.). Вы пишете программы в виде деревьев синтаксического разбора, которые создаются компиляторами, когда те выполняют синтаксический анализ других языков программирования. И эти деревья разбора полностью доступны для ваших программ. Вы можете писать программы, которые обрабатывают эти деревья. В Lisp, эти программы называются макросами. Это те программы, которые пишут программы. (Если вы никогда не хотите попасть в "Матрицу", вы должны быть довольны тем, что вы управляете Lisp-ом).

Мы знаем, что язык Java должен быть достаточно хорошим, поскольку это крутой язык программирования. Так ли это? В субкультуре хакеров, есть еще один язык, называемый Perl, который считается еще более крутым, чем Java. Но есть еще один язык, Python, пользователи которого обычно смотрят свысока на Perl, и есть еще один язык, называемый Ruby, который некоторые считают наследником языка Python.

Если вы будете рассматривать эти языки в указанном порядке - Java, Perl, Python и Ruby, то, если вы являетесь специалистом по Lisp, вы увидите интересную особенность. Каждый следующий из них все больше и больше похож на язык Lisp. Python копирует даже те особенности, которые многие специалисты по Lisp считают ошибочными. И если бы вы в 1975 году показали Ruby и описали его как диалект с синтаксисим языка Lisp, то никто с вами не стал бы спорить.

С 1958 года языки программирования почти догнали Lisp! Первоначально Lisp был создан Джоном Маккарти (John McCarthy) в 1958 году и только сейчас популярные языки программирования догнали те идеи, которые в нем были тогда разработаны.

Lisp просветит вас как личность

Все женатые мужчины будут солидарными со Стивеном Леви (Steven Levy), когда он в своей книге "Хакеры: Герои компьютерной революции" (Hackers: Heroes of the Computer Revolution) приводит пример того, как мыслят хакеры. Мардж Сондерс должна была утром в выходной день вернуться в гараж и попросила своего мужа Боба о следующем: "Есть ли у тебя желание помочь мне отнести продукты?". На что тот ответил: "Нет".

Ошеломленная, она должна была сама тянуть на себе продукты. После того, как то же самое произошло несколько раз, она взорвалась, посылая мужу проклятия и требуя объяснить, почему он всегда отвечает на ее вопрос - "Нет". "Глупо спрашивать", - сказал он. "Конечно, я не хочу помогать тебе нести продукты. Вот, если бы ты спросила, могу ли я помочь тебе их перенести, то это было бы другое дело".

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

С тех пор я узнал, что правильный ответ на вопрос Мардж Сондерс был бы: "Конечно, дорогая! Тебе нужно, чтобы я еще что-нибудь сделал для тебя?". Излишне говорить, что моя жена счастлива и в прошлом месяце мы отпраздновали наш седьмой год совместной семейной жизни.

Граница функционального программирования

В своей знаменитой работе "Why Functional Programming Matters" (Прим.пер.: Есть перевод этой статьи на русский язык — смотрите его по ссылке "Сильные стороны функционального программирования" ) эксперт по компьютерным наукам Джон Хьюз (R John M Hughes) говорит, что традиционные языки программирования смещают концептуальные ограничения в ту сторону, где проблемы могут быть решены с помощью разбиения на модули. Функциональные языки программирования снимают эти ограничения.

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

Начинаем

Любой язык, который подчиняется принципам языка Lisp, считается диалектом Lisp. Тем не менее, подавляющее большинство сообщества Lisp использует следующие две версии: ANSI Common Lisp (часто сокращаемый до CL) и Scheme. Здесь, я буду говорить исключительно о диалекте ANSI Common Lisp, чуть более популярном из двух этих диалектов.

Есть много отличных компиляторов Lisp. Но проще всего для начала воспользоваться пакетом CLISP — компилятором Common Lisp с открытым исходным кодом. Он прост в установке и работает в любой операционной системе — на платформах Windows, Mac и в различных вариантах Linux. Пользователи Mac, возможно, захотят воспользоваться компилятором LispWorks, который будет проще заставить работать на их машинах.

Устанавливаем CLISP

Вы можете скачать инсталлятор CLISP с официального сайта . В Windows, вы просто запускаете инсталляционную программу. Для Mac нужно выполнить несколько дополнительных настроек, которые подробно описаны на сайте. Для Linux-машин на базе Debian вы обнаружите, что CLISP уже существует в стандартных репозиториях программного обеспечения. Просто запустите в командной строке команду apt-get install clisp и CLISP будет у вас установлен автоматически. Для других дистрибутивов (Fedora, OpenSUSE и т.д.), вы можете воспользоваться стандартными пакетами, перечисленными на сайте CLISP в разделе "Пакеты для Linux" (если они отсутствуют в репозиториях дистрибутивов).

Запускаем его

Чтобы запустить CLISP, выполните в командной строке команду clisp . Если все пойдет по плану, то вы увидите приглашение к работе, показанное на рис.1.


Рис.1: Запуск CLISP

Точно также как и во всех средах Common Lisp, в среде языка CLISP после того, как вы его запустите, произойдет переход в режим "ввод — вычисление — выдача результата" (read-eval-print-loop, который называется циклом REPL). Это означает, что вы можете сразу же начать вводить код на языке Lisp. Попробуйте, набрав для этого строку (* 7 (+ 4 3)) . Ниже под набранным выражением вы увидите результат:

В выражении (* 7 (+ 4 3)) символы * и + называется операторами, а числа 7, 4 и 3 называются аргументами.

В повседневной жизни мы должны были бы писать это выражение как ((4 + 3) * 7), но в Lisp мы первым помещаем оператор, за которым идут аргументы, а все выражение заключаем в круглые скобки. Это называется префиксной нотацией, поскольку на первом месте стоит оператор.

Кстати, если вы допустили ошибку и CLISP начнет вести себя ненормально, просто наберите команду :q и все будет исправлено. Если вы хотите завершить работу CLISP, просто наберите команду ( quit ).

А что под "капотом"?

Давайте не будем идти традиционным путем, начиная изучать с азов (изучение синтаксиса языка, его основных функций и т.д.). Иногда, выяснение деталей, лежащих в основе, оказывается более трудным, чем общее понимание возможностей. Конрад Барский (Conrad Barski) пытаясь заинтересовать нас языком Lisp, показывает, как на нем написать игру. Давайте воспользуемся его методом и напишем простую игру с интерфейсом из командной строки, в которой используется алгоритм двоичного поиска.

Мы знаем, что методика двоичного поиска представляет собое деление данных на две части, что постепенно сужает область поиска до тех пор, пока не будет найдено совпадение или пока для обработки не будет больше элементов. Это классическая игра на отгадывание чисел. Попросите вашего друга (или, лучше - вашего начальника, которые не силен в технологиях, и который кричал на вас в последний раз, когда вы уснули во время заседания) выбрать (в уме) число от 1 до 100 и ваша программа на Lisp-е отгадает его не более, чем за 7 итераций.

Вот как Барский объясняет игру:

Чтобы создать эту игру, нам нужно написать три функции: guess-my-number (отгадывание-числа), smaller (число-меньше) и bigger (число-больше). Игрок просто вызывает эти функции в цикле REPL. Чтобы вызвать функцию в Lisp, вы должны заключить ее в скобки, а также указать любые параметры, которые вы хотите передать в функцию. Поскольку для этих функций не требуется никаких параметров, мы, когда входим в них, просто заключает названия этих функций в скобки.

Стратегия этой игры следующая:

  1. Определяем верхний и нижний пределы (наибольшее и наименьшее значения) числа, задуманного игроком. В нашем случае, наименьшим возможным числом будет 1, а наибольшим числом будет 100.
  2. Отгадываем число между этими двумя числами.
  3. Если игрок говорит, что число меньше, то уменьшаем верхний предел.
  4. Если игрок говорит, что число больше, то увеличиваем нижний предел.
  5. Нам также нужен механизм, позволяющий начать все сначала с другим номером.

В Common Lisp функции определяются с помощью определения defun следующим образом:

Когда игрок будет обращаться к функциям, которые составляют нашу игру, программе потребуется отслеживать нижний и верхний пределы. Чтобы делать это, нам нужно создать две глобальных переменных, которые будут называться *small* and *big* . Переменная, которая определяется в Lisp как глобальная, называется определением верхнего уровня. Мы можем с помощью функции defparameter создать новые определения верхнего уровня.

Звездочки, окружающие имена *big* и *small* , ласково называемые наушниками, выбраны совершенно произвольным образом и являются обязательными. Lisp рассматривает эти звездочки как часть имени переменной и игнорирует их как операции. У пользователей языка Lisp принято помечать глобальные переменные таким образом с тем, чтобы их можно было отличать от локальных переменных, которые будут рассмотрены в следующих статьях. Кроме того, когда Lisp читает ваш код, лишние пробелы и разрывы строк полностью игнорируется.

Теперь давайте определим первую функция, которая будет называться guess-my-number (отгадай мое число). В ней для отгадки числа, которое задумал игрок, будут использоваться значения переменных *big* и *small* . Определение будет выглядеть следующим образом:

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

Что делает эта функция? Как уже говорилось ранее, число, которое должен отгадать компьютер, будет лежать между двумя предельными значениями. Поэтому мы выбираем среднее значение, лежащее между двумя пределами. Но если среднее значение заканчивается дробной частью, мы будем использовать ближайшее к нему целое значение, поскольку мы отгадываем только целые числа.

Мы реализуем это в функции guess-my-number, добавив сначала цифры, которые представляют собой верхний и нижний пределы, затем с помощью функции арифметического сдвига ash делим пополам сумму пределов и сокращаем возможные результаты. Встроенная функция ash в Lisp берет число в двоичном виде и сдвигает его двоичные разряды влево или вправо, отбрасывая те биты, которые теряются в процессе сдвига. Например, число 11, записанное в двоичном формате, имеет вид 1011. Мы можем сдвинуть биты с помощью комады ash влево на 1 позицию, которая указывается в качестве второго аргумента:

Мы можем сдвинуть биты вправо (и отсечь бит, находящийся в конце), передав значение -1 в качестве второго аргумента:

Давайте посмотрим, что происходит, когда мы вызываем нашу новую функцию:

Поскольку это наша первая догадка, то значение, которое мы видим, когда вызываем эту функцию, указывает, что все происходит так, как и планировалось: программа выбрала номер 50, который как раз посередине между 1 и 100. Теперь, давайте напишем наши функции smaller и bigger. Точно также как и функция guess-my-number, они являюся глобальными функциями, определяемыми с помощью defun :

Во-первых, давайте воспользуемся defun для того, чтобы начать определение новой глобальной функции smaller. Затем воспользуемся функцией setf для изменения значения глобальной переменной *big*. Поскольку мы знаем, что число должно быть меньше, чем последняя догадка, наибольший предел должен быть на единицу меньше, чем последнее значение, предложенное в качестве догадки.

Это вычисляется с помощью кода (1- (guess-my-number)) следующим образом: сначала вызывается наша функция guess-my-number, которая берет самое последнее значение, предложенное в качестве догадки, и с помощью функции 1- из результата вычитается 1.

Наконец, мы хотим, чтобы наша функция smaller показала нам новую догадку. Мы делаем это, поместив вызов функции guess-my-number в последней строке в теле функции. На этот раз функция guess-my-number будет использовать обновленное значение *big*, в результате она вычислит следующую догадку. Окончательное значение нашей функции будет возвращено автоматически, в результате чего наша новая отгадка (сгенерированная функцией guess-my-number) должна быть возвращена функцией smaller.

Функция bigger работает точно так же, за исключением лишь того, что она увеличивает значение *small* . Если вы, в конечном счете, вызываете функцию bigger, вы говорите, что ваш номер больше, чем предыдущие предположение, так что наименьшее значение, которое загаданное число может принимать (которое теперь будет представлено переменной *small* ), будет на единицу больше, чем предыдущая догадка. Функция 1+ просто добавляет 1 к значению, возвращаемому функцией guess-my-number.

Чтобы завершить нашу игру, давайте добавим функцию start-over, которая будет перезагружать наши глобальные переменные:

Как вы видите, функция start-over перезагружает значения *small* и *big* , а затем снова вызывает функцию guess-my-number для того, чтобы выдать новую первоначальную догадку. Всякий раз, когда вы захотите начать совершенно новую игру с другим номером, вы можете вызвать эту функцию и перезагрузить игру.

На рис.2 наша игра показана в действии для случая, когда загадано число 74.


Рис.2: Игра в действии.

В следующих статьях мы вернемся к изучению с азов и начнем с базового синтаксиса и семантики языка.

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

Символьная обработка

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

Лисп опередил своё время

Лисп является наиболее важным языком программирования, используемым в исследованиях по искусственному интеллекту и в математической лингвистике. Название языка "Лисп" происходит из "list processing" (обработка списков). Буквально английское слово "lisp" означает "лепетать", "шепелявить" и "сюсюкать". В качестве имени языка программирования искусственного интеллекта это метко, поскольку именно с помощью Лиспа вычислительные машины научились в некоторой мере лепетать на человеческом языке.
И всё же Лисп ни в каком смысле не является младенцем. Скорее он старик среди языков программирования. Лисп разработан уже в 50-х годах и является вслед за Фортраном старейшим ещё используемым языком программирования. Но в отличие от Фортрана будущее Лиспа ещё впереди.
Лисп представляет собой язык так называемого функционального программирования. Он основан на алгебре списочных структур, лямбда-исчислении и теории рекурсивных функций. Благодаря неразвитости традиционной вычислительной техники, отличающемуся от других языков программирования характеру и из-за наличия элементарных средств обработки списков Лисп долгое время являлся основным инструментом исследователей искусственного интеллекта и средством теоретического подхода к анализу программирования. Однако в 80-х годах Лисп, наконец, вышел из лабораторий и нашел применение в прикладных проблемах.
Обычно языки программирования не изобретают, а проектируют. Однако по отношению к Лиспу можно говорить об изобретении. Первоначальная версия языка, в частности, содержала множество понятий и принципов, которые сначала казались очень странными, но многие из которых позже оказались существенным нововведением. Кроме этого, возможность добавления в Лисп в течение десятилетий многих новых черт подтвердила свойство расширяемости этого языка. Вокруг Лиспа возникла широкая культура, охватывающая многочисленные школы и разнообразные диалекты языка, различные системы и методы программирования, программные среды и Лисп-машины.
Далее мы коротко рассмотрим многочисленные свойства Лиспа и его отличия от других языков программирования.

Одинаковая форма данных и программы

В Лиспе формы представления программы и обрабатываемых ею данных одинаковы. И то и другое представляется списочной структурой, имеющей одинаковую форму. Таким образом программы могут обрабатывать и преобразовывать другие программы и даже самих себя. В процессе трансляции можно введённое и сформированное в результате вычислений выражение данных интерпретировать в качестве программы и непосредственно выполнить. Предоставленная этим возможность так называемого программирования, управляемого данными, и непосредственное влияние программы на программу тесно связаны между собой.
Это свойство обладает не только теоретическим, но и большим практическим значением. Единообразность представления данных и программы можно сопоставить с принципом фон Неймана, по которому программа и данные хранятся в единой памяти. Благодаря этому появилась великолепная возможность создания универсальной вычислительной машины обработки данных. Соответственно единообразное представление программы и данных и реализация программы путем интерпретации открывают совершенно новые возможности программирования.
Универсальный единообразный и простой синтаксис списка не зависит от применения, и с его помощью легко определять новые формы записи, представления и абстракции. Даже сама структура языка является, таким образом, расширяемой и может быть заново определена. В то же время достаточно просто написания интерпретаторов, компиляторов, преобразователей, редакторов и других средств. К Лиспу стоит подойти как к языку программирования, с помощью которого реализуются специализированные языки, ориентированные на приложение, и создается окружение более высокого уровня. Присущая Лиспу гибкая расширяемость не встречается в традиционных замкнутых языках программирования.

Хранение данных, не зависящее от места

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

Автоматическое и динамическое управление памятью

Пользователь не должен заботится об учёте памяти. Система резервирует и освобождает память автоматически в соответствии с потребностью. Когда память кончается, запускается специальный мусорщик. Он собирает неиспользуемые символы и списки, включает их в работу путём вторичного использования. Среда Лиспа постоянно содержится в порядке. Управление памятью просто и не зависит от физического расположения, поскольку свободная память логически состоит из цепочки списочных ячеек.
В первую очередь данные обрабатываются в оперативной и виртуальной памяти, которая может быть довольно большой. Файлы используются в основном для хранения программ и данных в промежутке между сеансами.

Функциональный образ мышления

Используемое в Лиспе так называемое функциональное программирование основывается на той простой идее, что в результате каждого действия возникает значение. Значения становятся аргументами следующих действий, и конечный результат всей задачи выдаётся пользователю.
Программы строятся из логически расчленённых определений функций. Определения состоят из управляющих структур, которые организуют вычисления и из вложенных, часто вызывающих самих себя (рекурсивных) вызовов функций. Основными средствами функционального программирования как раз и являются композиция и рекурсия.

Возможность различных методов программирования

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

Пошаговое программирование

Программирование и тестирование программы осуществляется функция за функцией, которые пошагово определяются и подвергаются тестированию. Такой подход называют пошаговым программированием. Написание, тестирование и исправление программы осуществляется внутри Лисп-системы без промежуточного использования операционной системы. Специальные операционные системы более не используются, точнее они скрыты от пользователя. Все услуги имеются в интегрированной системе программирования.
Вспомогательные средства, находящиеся в распоряжении пользователя, такие как, например редактор, инспектор, транслятор, структурная печать и другие образуют общую интегрированную среду, язык которой нельзя чётко отличить от системных средств. Отдельные средства по своему принципу являются прозрачными, чтобы их могли использовать другие средства. Например, интерпретатор может вызвать редактор. Редактор - интерпретатор и так далее даже рекурсивно. Работа может производится часто на различных уровнях или в различных рабочих окнах. Такой способ работы особенно хорошо подходит для исследовательского программирования и быстрого построения прототипов.

Лисп - язык программирования без закрепления типов

В Лиспе имена символов, переменных, списков, функций и других объектов не закреплены предварительно за какими-нибудь типами данных. Типы в общем не связаны с именами объектов данных, а сопровождают сами объекты. Таким образом, переменные могут в различные моменты времени представлять различные объекты. В этом смысле Лисп является языком без закрепления типов.
Например, в Фортране имена переменных, начинающиеся с букв I, J и K, закреплены за целыми числами уже с момента определения языка в 50-х годах. В Паскале тип переменной закрепляется на этапе написания программы. В некоторых языках тип переменной определяется на этапе трансляции. В Лиспе тип определяется по ходу выполнения программы.
Динамическая, осуществляемая лишь в процессе исполнения, проверка типа и позднее связывание допускают разностороннее использование символов и гибкую модификацию программ. Функции можно определять практически независимо от типов данных, к которым они применяются.
Однако указанная не-закреплённость типов не означает, что в Лиспе вовсе нет данных различных типов. Мы далее увидим, что набор типов данных наиболее развитых Лисп-систем необычайно разнообразен.
Одним из общих принципов развития Лисп-систем было свободное включение в язык новых возможностей и структур, если считалось, что они найдут более широкое применение. Это было возможно в связи с естественной расширяемостью языка.
Платой за динамические типы являются действия по проверке типа на этапе исполнения. В Лисп-машинах проверка типа эффективно осуществляется на уровне аппаратуры.

Единый системный и прикладной язык программирования

Лисп является одновременно как языком прикладного, так и системного программирования. Он напоминает машинный язык тем, что как данные, так и программа представлены в одинаковой форме. Язык превосходно подходит для написания интерпретаторов и трансляторов как для него самого, так и для других языков. Например, ядро интерпретатора Лиспа, написанное на самом Лиспе, составляет пару страниц красивого кода. Примерно в том же объёме уместится и ядро интерпретатора Пролога. Как известно, наиболее короткий интерпретатор Пролога, написанный на Лиспе занимает несколько десятков строк.
Традиционно Лисп-системы в основной своей части написаны на Лиспе. При программировании, например транслятора, есть возможность для оптимизации объектного кода использовать сложные преобразования и методы искусственного интеллекта. Лисп можно в хорошем смысле считать языком машинного и системного программирования высокого уровня. И это особенно характерно для Лисп-машин, которые вплоть до уровня аппаратуры спроектированы для Лиспа и системное программное обеспечение которых написано на Лиспе.

Интегрированная среда программирования

Лисп-системы и среды программирования развиваются уже начиная с конца 50-х годов. С самого начала разработки в них был заложен принцип возможности использования отдельных средств непосредственно из интерпретатора.
В реализациях для микроЭВМ количество системных и встроенных функций обычно ограничивается порядком десяти, сотни. В больших системах разделения времени, таких как Маклисп и Интерлисп, функций многие сотни. Коммон Лисп и автоматизированные рабочие места (рабочие станции) для исследователей искусственного интеллекта и Лисп-машины предлагают особенно широкий выбор различных вспомогательных средств и функций интегрированной среды, которая, кроме всего прочего, открыта для модификаций пользователя.
Системное программное обеспечение Лисп-машин содержит более 10000 функций и десятки мегабайтов кода. Во многих системах исходные тексты кода Лисп предоставляются пользователю. Системные функции можно переопределить или модифицировать, и пользователь может свободно расширить и подогнать систему для себя.

Широко распространённые заблуждения и предрассудки

Про Лисп говорят, что это неэффективный язык, особенно в части арифметики. Это было верно на начальном этапе. На численную сторону не обращалось внимание, поскольку язык был предназначен для символьной обработки. Теперь это уже не так. Лисп-системы могут в численных вычислениях быть более эффективными, чем Фортран на той же машине. Это объясняется в том числе и тем, что в трансляторах с Лиспа можно применять более сложные преобразования для оптимизации кода.
Естественным является то, что большие системы, предлагающие многосторонние и разумные услуги, требуют большой вычислительной мощности и громоздки для системы разделения времени. Однако это связано не с Лиспом или его плохой реализацией, а с тем вниманием и с той готовностью помочь, которые система предлагает пользователю.
Например, Интерлисп сохраняет полный перечень всех действий пользователя и полное описание более ранних состояний системы и способен автоматически исправлять многие неточности, как, например, ошибки в написании. Если эти свойства правильно использовать, то они повышают производительность профессионального программиста в большей степени, чем тратят ресурсы машины.
С точки зрения программирования критике подвергается и внешний облик языка: изобилие скобок и кажущийся беспорядок. Лисп ("Lots if Idiotic Silly Parentheses") представляется как трудно-понимаемый и трудно-изучаемый язык.
Такой подход проистекает из используемых в Лиспе функционального образа мышления и техники программирования, которые чужды программистам, привыкшим к операторному программированию традиционных языков. Естественно используемые в программировании на Лиспе структуры данных и управляющие структуры часто сложны, поскольку проблемы искусственного интеллекта из-за своей сложности предполагают сложные структуры и программы. Иерархические списочные структуры и Лисп как раз и задумывались для работы со сложными проблемами. Искусственное упрощение структур означало бы пренебрежение действительной сложностью проблем.
Идеей Лиспа является попытка упростить решение проблемы, структурируя используемые данные и упрощая программы. Такой подход оказался полезным, например, в объектно-ориентированном программировании и в экспертных системах. Эти области содержат больше количество знаний со сложной структурой, которые интерпретируются часто довольно простыми процедурами поиска и принятия решения.

Простой и эффективный язык

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

Более сорока лет назад разработан и внедрен в использование для выполнения целей искусственного интеллекта язык программирования LISP (ЛИСП), позднее ставший популярным среди пользователей ПО AutoCAD. Он создан для символьных вычислений. С течением времени был преобразован, чтобы соответствовать новым потребностям ИИ.

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

Это imperative language (императивный), действия которого описывают выполнение алгоритма, отличается от других, декларативных, предполагающих определение ограничений и соотношений в предметной сфере поставленной цели. По сравнению с другими подобными разработками С++ и FORTRAN, ЛИСП наделен большей функциональностью. Его популярность обусловлена большими возможностями для программирования в сочетании с мощным набором:

Это средства построения данных структур обозначения высокого уровня.

Конструкция

LISP синтаксис и семантика, разработанные программистами, обусловлены теорией рекурсивных функций. Символьные, s-выражения, являются элементами предложений, сочетаний. В них представлены софты и файлы. Они могут отображаться в виде списка (list) или атомов (atom).

Во втором варианте включены числовые комбинации, цифры, буквы латинского алфавита и знаки: *, -, +, /,@, %, , &, _, , ~.

язык lisp

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

установка lisp

Язык LISP относится к языкам программирования, которые используются для создания дополнительных загрузок к ПО по проектированию и моделированию. Для их использования необязательно хорошо разбираться в компьютере на уровне профессионала.

После изучения основных принципов работы в таких пакетах, как AutoCAD или ZWCAD Professional, который является аналогом ACAD, появляется необходимость упростить выполнение длительных рутинных операций или полностью избавиться от них. Для этого дополнения и нужны. Если они написаны на ЛИСПе, скрипты называются LISP-приложения. Каждое из них представляет собой текстовый файл с определенным встроенным кодом для выполнения команды и подсказками от производителя. Определитесь с нужными для работы свойствами, выбирайте надстройку, скачивайте ее и загружайте в ZWCAD или другую платформу. Начиная с версии ZWCAD 2020, в платформу встроен Отладчик Lisp приложений, разработанный на базе Visual Studio Code от Microsoft.


Lisp является аббревиатурой для LISt Processing Language — основным списком в структуре языка. Эти семейные языки позволяют специалистам записывать программы, которые работают быстрее, чем на других языках. Язык программирования Лисп и его диалекты такие как Common, Scheme и Clojure, способствуют созданию мощного и гибкого программного обеспечения, необходимого для сложных и быстро развивающихся областей науки и техники.

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

История

История семейных языков LISP

Лисп является вторым старейшим языком высокого уровня (после FORTRAN), впервые разработанным Джоном Маккарти (Массачусетский технологический институт). Хотя он используется в качестве программного языка во многих областях науки, но после Дартмутской конференции 1956 года, которая считается местом рождение дисциплины искусственного интеллекта(ИИ), он в первую очередь идентифицируется с этой областью науки в течение многих лет.

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

Еще один ранний диалект - Lisp-Scheme — сохранился до наших дней, является стандартизированным и широко используемым языком для программирования с нуля. Хотя он похож на Лисп, но отличается от него некоторыми элементами, которые позволяют рассматривать его как отдельный язык.

Ключевые моменты программирования

Лисп позволяет программистам писать быстрее. Эмпирическое исследование показывает, что когда специалисты решают те же проблемы в Lisp, C / C ++ и Java, то программы Лисп меньше, и, следовательно, их легче поддерживать, требуется меньше времени для разработки и запуска. Язык программирования Лисп упрощает создание макросов, которые облегчают создание модульных расширений, чтобы помочь специалистам легко разрабатывать плагины для программного обеспечения. Это, в свою очередь, открывает путь для создания отказоустойчивых доменных языков в приложениях любой области исследований или специализации.

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

Базовая концепция

Базовая концепция программирования

Lisp является самым ранним представителем парадигмы языка функционального программирования с нуля. В отличие от процедурных и объектно-ориентированных языков, теоретическая модель которых является машиной Тьюринга, теоретической моделью расчета Лиспа является исчисление Лямбды, разработанное церковью Алонсо. Это различие может быть понято в по следующим направлениям:

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

Интерактивность и гибкость

Интерактивность и гибкость языка

Скорость языков Lisp обычно эквивалентна интерпретируемым языкам. Это также является источником старого мифа о том, что если он интерпретируется, то, следовательно, должен быть медленным, однако это не так. Компиляторы для Лисп существуют с 1959 года, и теперь все основные реализации Common Лисп могут быть скомпилированы непосредственно с машинным кодом, который часто совпадает с кодом C. Например, CL—PPCRE библиотека выражений, написанная в Common Лисп, работает быстрее, чем движок регулярного выражения Perl на некоторых тестах в C, а обучение Lisp намного проще.

Программисты, которые используют интерпретируемые языки, такие как Python или Perl, для удобства и гибкости должны прибегать к написанию на C /C ++ для критически важных частей своего кода и имеют для этого уникальные возможности. Это было показано с прямым бенчмаркингом со стороны создателя языка программирования R, Росса Ихаки, который предоставил тесты, демонстрирующие, что необязательное объявление типа Lisp и компилятор машинного кода позволяют использовать их в 380 раз быстрее, чем R, и в 150 раз быстрее Python.

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

Оценка специальных форм и макросов

Если первым символом в списке, подлежащем оценке, является имя специальной формы или макроса, так как интерпретатор не оценивает аргументы. Однако специальная форма или макрос могут оценивать некоторые из аргументов, как это обрабатывается, варьируется в специальной форме макроса. Например, специальная форма setq оценивает второй аргумент, но не первый. Пример: рассмотрим вторую строку следующего фрагмента кода: (setq a 1) (setq a (+ 2 3)).

Так как специальная форма setq оценивает свой второй аргумент, форма (+ 2 3) оценивается, получая 5. Однако форма не оценена как 5, а назначена. Если setq была функцией или специальной формой, которая оценивала оба аргумента, операция означала бы, что 5 должно быть равно 1, что, очевидно, абсурдная операция!

Некоторые формы и функции

Некоторые формы и функции

Ниже перечислены лишь некоторые из специальных форм, макросов и lisp-функции. Некоторые специальные формы и макросы Quote являются специальной формой, которая просто передает свой неоценимый аргумент. Например, значение (quote a) символа a. Для удобства считается, что выражение формы anything эквивалентно (quote anything).

Setq - это специальная форма, которая оценивает свой второй аргумент, а затем присваивает значение переменной, названной ее аргументом.

Let является специальной формой, которая создает лексические переменные. Она имеет следующую базовую форму: (let ( <( переменное выражение )>*) < form >*). Формы оцениваются в контексте, в котором каждая из переменных является лексической переменной, связанной с указанным начальным значением. Все выражения вычисляются до того, как какая-либо из переменных привязана, поэтому выражение не может использовать ранее объявленную переменную let.

If является специальной формой, которая выбирает одно из двух выражений для оценки на основе результата какого-либо теста, причем его значение становится значением всего выражения. Это аналогично условному выражению языков C-семейства. Две формы должны быть одиночными s-выражениями, однако progn можно использовать для группировки нескольких форм (аналогично < . >Java), хотя это, конечно, не чисто функциональный стиль.

Форма else может быть опущена, в этом случае, если тест ложный, результат будет nil. Cond - это макрос, который выбирает одну серию выражений из нескольких для оценки. Он имеет следующую базовую форму (cond <( test

*)> *). Каждый тест оценивается поочередно, пока не будет возвращен какой-либо результат, кроме nil - в этот момент будет оценена следующая форма. Значение последней оцениваемой формы становится значением cond.

And — макрос с любым количеством аргументов, которые обычно являются всеми тестами - true.

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

Defun - макрос для определения названных функций. Основной синтаксис (defun name ( < parameter >*) < form >*).

Lambda — макрос для определения анонимных функций.

Операции со списками

Операции со списками

Функциональные языки программирования Лисп означают, что аргументы оцениваются до выполнения операции cons- 2 аргумента любого типа. Создает пунктирную пару (cons cell), состоящую из 2 аргументов:

  • (cons 'a 3) - это (a . 3) car- 1 аргумент, который должен быть истинным или пунктирным списком. Извлекает car первой ячейки списка.
  • (car '(a 3)) - это a. cdr- 1 аргумент, который должен быть истинным или пунктирным списком. Извлекает cdr первой ячейки списка. Если список состоит из более чем одной ячейки, его cdr сам будет списком.

(cdr '(a 3)) - есть (3). caar, cdar, cadr, cddr и еще несколько - любое сочетание до четырех элементов.

List- различное количество аргументов любого типа. Преобразует свои аргументы в настоящий список. Например, (list 'a 'b '(1 2)) - это (a b (1 2)) append- любое количество аргументов - все, кроме последнего, должны быть истинными списками. Объединяет его аргументы в один список, который будет истинным. Например, (append '(1 2) '(3 4)) - это (1 2 3 4).

Арифметические операции

Арифметические операции

Lisp - язык программирования, который поддерживает арифметические операции, обнаруженные на большинстве языков программирования, а также множество уникальных. Большинство операций принимают любое количество аргументов, например, (* 2 3 4 5) оцениваются до 120.

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

  • Сложение — любое количество аргументов, без аргументов дает единичный элемент для сложения, 0 – отрицание — один аргумент, вычитание – два или более аргумента, незаконным без аргументов.
  • Умножение — любое количество аргументов, без аргументов дает единичный элемент для умножения, 1. /взаимный — один аргумент.
  • Деление – два или более аргумента.

Использования в AutoCAD

Использования в AutoCAD

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

Загрузка файла Lisp языка программирования:

  1. Ввести APPLOAD в командную строку и нажать Enter.
  2. Перейти в папку autolisp и щелкнуть нужный файл Lisp, затем нажать LOAD, а затем ЗАКРЫТЬ.

Использование файла Lisp:

Искусственный интеллект Franz

Искусственный интеллект Franz

Franz Lisp является первым изобретением в области искусственного интеллекта от ведущего поставщика технологий Semantic Graph Database. AllegroGraph - это сверхмасштабируемая, высокопроизводительная и транзакционная база данных семантического графика, которая превращает сложные данные в эффективные бизнес-идеи. Allegro CL обеспечивает идеальную среду программирования Lisp для создания сложных критически важных приложений, которые решают проблемы реального мира.

Franz Inc. стремится к разработке продуктов на основе рынка, наивысшему уровню качества продукции и гибкой поддержке и обслуживанию клиентов. Клиенты Franz включают в себя десятки компаний из списка Fortune 500, которые охватывают здравоохранение, разведывательные агентства, науки о жизни, телекоммуникации и перспективные исследовательские организации, и ищут решения для сложных проблем.

Области применения

В 1980-х и 1990-х годах были предприняты огромные усилия для объединения областей применения языка Лисп. Результатом стала стандартизация Коммон Лисп, стандарт ANSI которой был опубликован в 1994 году, а также более известный пользователям расширение ISO выпущенного в 1997 на его основе ISLISP ISO и пересмотренный в 2007 году стандарт ISO / IEC 13816: 2007 (E) .

В то время Лисп был гораздо более популярным, чем в настоящее время. Несмотря на более популярные языки, близкие машине (C, C ++), Lisp остается довольно используемым языком, особенно в качестве встроенного языка в приложениях, где он служит языком расширения. Наиболее известный случай Lisp встраивается использовать текстовый редактор Emacs и язык AutoLISP в AutoCAD .

Lisp занимает четвертое место в строках кода, используемых для реализации исходных пакетов из 8 600, доступных в операционной системе Debian, выпущенных в июне 2005 года. Первые восемь языков распределяются следующим образом: C (57 %) , C ++ (16,8 %), Shell (9 %), Lisp (3 %), Perl (2,8 %), Python (1,8 %), Java (1,6 %), Fortran (1,2 %). В июле 2013 года Лисп находился на 15-й позиции индекса TIOBE.

Сегодня существует еще несколько популярных вариантов Lisp, например:

  1. Common Lisp.
  2. Scheme.
  3. EmacsLisp , для программирования редактора Emacs.

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

Читайте также: