common-lisp учебник
Начало работы с общими
Поиск…
замечания
Это простая функция hello world в Common Lisp. Примеры напечатают текст Hello, World!
(без кавычек, за которым следует новая строка) до стандартного вывода.
Common Lisp - это язык программирования, который в основном используется интерактивно с использованием интерфейса, известного как REPL. REPL (Read Eval Print Loop) позволяет вводить код, оценивать (запускать) и сразу видеть результаты. Запрос для REPL (в какой момент один из них вводит код, который должен быть запущен) обозначается CL-USER>
. Иногда перед >
должен появляться нечто иное, кроме CL-USER
, но это все еще REPL.
После запроса появляется код, обычно либо одно слово (то есть имя переменной), либо форма (список слов / форм, заключенных между (
и )
) (т. Е. Вызов функции или объявление и т. Д.). На следующей строке будет любой вывод, который программа печатает (или ничего, если программа ничего не печатает), а затем значения, возвращаемые путем вычисления выражения. Обычно выражение возвращает одно значение, но если оно возвращает несколько значений, они появляются один раз в строке.
Версии
Версия | Дата выхода |
---|---|
Общий Лисп | 1984-01-01 |
ANSI Common Lisp | 1994-01-01 |
Привет, мир
Ниже следует отрывок из сеанса REPL с Common Lisp, в котором «Hello, World!» функция определена и выполнена. См. Замечания в нижней части этой страницы для более подробного описания REPL.
CL-USER> (defun hello ()
(format t "Hello, World!~%"))
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER>
Это определяет «функцию» нулевых аргументов с именем hello
, которая будет писать строку "Hello, World!"
за которым следует новая строка для стандартного вывода и возвращаем NIL
.
Чтобы определить функцию, напишем
(defun name (parameters...)
code...)
В этом случае функция называется hello
, не принимает никаких параметров, а код, который он запускает, - это один вызов функции. Возвращаемое значение из функции lisp - это последний бит кода в функции для запуска, так что hello
возвращается (format t "Hello, World!~%")
возвращается (format t "Hello, World!~%")
.
В lisp для вызова функции write (function-name arguments...)
где function-name
- это имя функции, а arguments...
- это список аргументов (разделенных пробелами) для вызова. Существуют некоторые особые случаи, которые выглядят как вызовы функций, но не являются, например, в приведенном выше коде не существует функции defun
, вызываемой, она обрабатывается специально и определяет функцию вместо этого.
Во втором приглашении REPL, после того как мы определили функцию hello
, мы вызываем его без параметров, записывая (hello)
. Это, в свою очередь, вызовет функцию format
с параметрами t
и "Hello, World!~%"
. Функция format
производит форматированный вывод на основе аргументов, которые он задает (немного похож на расширенную версию printf
в C). Первый аргумент указывает, куда выводить, с t
значением standard-output. Второй аргумент говорит, что печатать (и как интерпретировать любые дополнительные параметры). Директива (специальный код во втором аргументе) ~%
сообщает формату печати новой строки (т.е. в UNIX она может писать \n
и на windows \r\n
). Формат обычно возвращает NIL
(немного как NULL
на других языках).
После второго запроса мы видим, что Hello, World
был напечатан, а на следующей строке возвращаемое значение было NIL
.
Привет, Имя
Это немного более продвинутый пример, который показывает еще несколько функций общего lisp. Начнем с простого Hello, World!
функции и продемонстрировать некоторые интерактивные разработки на REPL. Обратите внимание, что любой текст из точки с запятой ;
, остальная часть строки - комментарий.
CL-USER> (defun hello ()
(format t "Hello, World!~%")) ;We start as before
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> (defun hello-name (name) ;A function to say hello to anyone
(format t "Hello, ~a~%" name)) ;~a prints the next argument to format
HELLO-NAME
CL-USER> (hello-name "Jack")
Hello, Jack
NIL
CL-USER> (hello-name "jack") ;doesn't capitalise names
Hello, jack
NIL
CL-USER> (defun hello-name (name) ;format has a feature to convert to title case
(format t "Hello, ~:(~a~)~%" name)) ;anything between ~:( and ~) gets it
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello-name "jack")
Hello, Jack
NIL
CL-USER> (defun hello-name (name)
(format t "Hello, ~:(~a~)!~%" name))
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello-name "jack") ;now this works
Hello, Jack!
NIL
CL-USER> (defun hello (&optional (name "world")) ;we can take an optional argument
(hello-name name)) ;name defaults to "world"
WARNING: redefining COMMON-LISP-USER::HELLO in DEFUN
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> (hello "jack")
Hello, Jack!
NIL
CL-USER> (hello "john doe") ;note that this capitalises both names
Hello, John Doe!
NIL
CL-USER> (defun hello-person (name &key (number))
(format t "Hello, ~a ~r" name number)) ;~r prints a number in English
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16) ;this doesn't quite work
Hello, Louis sixteen
NIL
CL-USER> (defun hello-person (name &key (number))
(format t "Hello, ~:(~a ~:r~)!" name number)) ;~:r prints an ordinal
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16)
Hello, Louis Sixteenth!
NIL
CL-USER> (defun hello-person (name &key (number))
(format t "Hello, ~:(~a ~@r~)!" name number)) ;~@r prints Roman numerals
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16)
Hello, Louis Xvi!
NIL
CL-USER> (defun hello-person (name &key (number)) ;capitalisation was wrong
(format t "Hello, ~:(~a~) ~:@r!" name number))
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16) ;thats better
Hello, Louis XVI!
NIL
CL-USER> (hello-person "Louis") ;we get an error because NIL is not a number
Hello, Louis ; Evaluation aborted on #<SB-FORMAT:FORMAT-ERROR {1006641AB3}>.
CL-USER> (defun say-person (name &key (number 1 number-p)
(title nil) (roman-number t))
(let ((number (if number-p
(typecase number
(integer
(format nil (if roman-number " ~:@r" " ~:(~:r~)") number))
(otherwise
(format nil " ~:(~a~)" number)))
"")) ; here we define a variable called number
(title (if title
(format nil "~:(~a~) " title)
""))) ; and here one called title
(format nil "~a~:(~a~)~a" title name number))) ;we use them here
SAY-PERSON
CL-USER> (say-person "John") ;some examples
"John"
CL-USER> (say-person "john doe")
"John Doe"
CL-USER> (say-person "john doe" :number "JR")
"John Doe Jr"
CL-USER> (say-person "john doe" :number "Junior")
"John Doe Junior"
CL-USER> (say-person "john doe" :number 1)
"John Doe I"
CL-USER> (say-person "john doe" :number 1 :roman-number nil) ;this is wrong
"John Doe First"
CL-USER> (defun say-person (name &key (number 1 number-p)
(title nil) (roman-number t))
(let ((number (if number-p
(typecase number
(integer
(format nil (if roman-number " ~:@r" " the ~:(~:r~)") number))
(otherwise
(format nil " ~:(~a~)" number)))
""))
(title (if title
(format nil "~:(~a~) " title)
"")))
(format nil "~a~:(~a~)~a" title name number)))
WARNING: redefining COMMON-LISP-USER::SAY-PERSON in DEFUN
SAY-PERSON
CL-USER> (say-person "john doe" :number 1 :roman-number nil) ;thats better
"John Doe the First"
CL-USER> (say-person "louis" :title "king" :number 16 :roman-number nil)
"King Louis the Sixteenth"
CL-USER> (say-person "louis" :title "king" :number 16 :roman-number t)
"King Louis XVI"
CL-USER> (defun hello (&optional (name "World") &rest arguments) ;now we will just
(apply #'hello-name name arguments)) ;pass all arguments to hello-name
WARNING: redefining COMMON-LISP-USER::HELLO in DEFUN
HELLO
CL-USER> (defun hello-name (name &rest arguments) ;which will now just use
(format t "Hello, ~a!" (apply #'say-person name arguments))) ;say-person
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello "louis" :title "king" :number 16) ;this works now
Hello, King Louis XVI!
NIL
CL-USER>
Это освещает некоторые дополнительные функции функции format
Common Lisp, а также некоторые функции, такие как необязательные параметры и аргументы ключевых слов (например, :number
). Это также дает пример интерактивной разработки в REPL в общем lisp.
Простая программа Hello World в REPL
Common Lisp REPL - это интерактивная среда. Каждая форма, написанная после запроса, оценивается, и ее значение впоследствии печатается в результате оценки. Итак, самая простая программа Hello, World! В Common Lisp:
CL-USER> "Hello, World!"
"Hello, World!"
CL-USER>
Что происходит здесь, так это то, что строковый costant задается во вводе REPL, он вычисляется и результат печатается. Из этого примера видно, что строки, такие как числа, специальные символы, такие как NIL
и T
и несколько других литералов, являются самооценками : они сами оценивают.
Основные выражения
Попробуем некоторое базовое выражение в REPL:
CL-USER> (+ 1 2 3)
6
CL-USER> (- 3 1 1)
1
CL-USER> (- 3)
-3
CL-USER> (+ 5.3 (- 3 2) (* 2 2))
10.3
CL-USER> (concatenate 'string "Hello, " "World!")
"Hello, World!"
CL-USER>
Основной строительный блок Common Lisp - это форма . В этих примерах мы имеем формы функций , то есть выражения, написанные как список, в которых первый элемент является оператором (или функцией), а остальные элементы являются операндами (это называется «Префиксная нотация» или «Польская нотация» «). Написание форм в REPL вызывает их оценку. В примерах вы можете увидеть простые выражения, аргументы которых являются постоянными числами, строками и символами (в случае 'string
, которая является именем типа). Вы также можете видеть, что арифметические операторы могут принимать любое количество аргументов.
Важно отметить, что круглые скобки являются неотъемлемой частью синтаксиса и не могут использоваться свободно, как в других языках программирования. Например, следующая ошибка:
(+ 5 ((+ 2 4)))
> Error: Car of ((+ 2 4)) is not a function name or lambda-expression. ...
В общих формах Лиспа также могут быть данные, символы, макроформы, специальные формы и формы лямбда. Они могут быть записаны для оценки, возврата нуля, одного или нескольких значений или могут быть заданы во вводе макроса, которые преобразуют их в другие формы.
Сумма списка целых чисел
(defun sum-list-integers (list)
(reduce '+ list))
; 10
(sum-list-integers '(1 2 3 4))
; 55
(sum-list-integers '(1 2 3 4 5 6 7 8 9 10))
Лямбда-выражения и анонимные функции
Анонимная функция может быть определена без имени через выражение Lambda . Для определения этих типов функций вместо ключевого слова defun
используется ключевое слово lambda
. Следующие строки эквивалентны и определяют анонимные функции, которые выводят сумму двух чисел:
(lambda (x y) (+ x y))
(function (lambda (x y) (+ x y)))
#'(lambda (x y) (+ x y))
Их полезность заметна при создании Лямбда-форм , то есть в форме, которая представляет собой список, в котором первым элементом является лямбда-выражение, а остальные элементы являются аргументами анонимной функции. Примеры ( онлайн-исполнение ):
(print ((lambda (x y) (+ x y)) 1 2)) ; >> 3
(print (mapcar (lambda (x y) (+ x y)) '(1 2 3) '(2 -5 0))) ; >> (3 -3 3)
Общие учебные ресурсы Lisp
Интернет-книги
Это книги, которые свободно доступны в Интернете.
- Практический общий Lisp от Peter Seibel - хорошее введение в CL для опытных программистов, которое с самого начала пытается подчеркнуть, что делает CL отличным от других языков.
- Common Lisp: Нежное введение в символические вычисления Дэвида С. Туретцкого - хорошее введение для людей, новых для программирования.
- Common Lisp: интерактивный подход Стюарта Шапиро был использован в качестве учебника курса, и примечания к курсу сопровождают книгу на веб-сайте.
- Common Lisp, Language by Guy L. Steele - это описание языка Common Lisp. Согласно CLiki, он устарел, но содержит более подробные описания макроса цикла и формата, чем это делает Common Lisp Hyperspec.
- На Lisp by Paul Graham - отличная книга для опытных мастеров Лисперса.
- Let Over Lambda от Doug Hoyte - это передовая книга о Lisp Macros. Несколько человек рекомендовали вам комфортно работать с Lisp перед тем, как прочитать эту книгу, и что начало происходит медленно.
Интернет-ссылки
- Common Lisp Hyperspec - это справочный документ для Common Lisp.
- Common Lisp Cookbook - это список полезных рецептов Lisp. Также содержит список других онлайн-источников информации CL.
- В Common Lisp Quick Reference есть листы для печати Lisp.
- Lispdoc.com ищет несколько источников информации о Lisp (Practical Common Lisp, Successful Lisp, On Lisp, HyperSpec) для документации.
- L1sp.org - это служба переадресации для документации.
Не в сети
Это книги, которые вам, вероятно, придется купить или получить в библиотеке.
- ANSI Common Lisp от Paul Graham .
- Общие рецепты Лиспа от Эдмунда Вейца .
- В парадигмах программирования искусственного интеллекта есть много интересных приложений Lisp, но это не является хорошей ссылкой для AI.
Интернет-сообщества
- CLiki имеет отличную начальную страницу . Отличный ресурс для всех вещей CL. Имеет обширный список книг Лиспа .
- Common Lisp subreddit имеет множество полезных ссылок и справочных документов на боковой панели.
- IRC: #lisp, #ccl, #sbcl и другие на Freenode .
- Common-Lisp.net предоставляет хостинг для многих общих проектов lisp и групп пользователей.
Библиотеки
- Quicklisp является библиотечным менеджером для Common Lisp и имеет длинный список поддерживаемых библиотек .
- QuickDocs размещает библиотечную документацию для многих библиотек CL.
- Awesome CL - это кураторский список библиотек, фреймворков и других блестящих материалов, отсортированных по категориям.
Предварительно упакованные среды Lisp
Это среды редактирования Lisp, которые легко установить и начать работу, потому что все, что вам нужно, предварительно упаковано и предварительно настроено.
- Portacle - это переносная и многоплатформенная среда Common Lisp. Он отправляет слегка настроенные Emacs со Slime, SBCL (популярная реализация Common Lisp), Quicklisp и Git. Никакой установки не требуется, так что это очень быстрый и простой способ добиться успеха.
- Lispbox - это среда IDE (Emacs + SLIME), Common Lisp (Clozure Common Lisp) и менеджер библиотек (Quicklisp), предварительно упакованные в виде архивов для Windows, Mac OSX и Linux. Потомок «Лиспа в коробке», рекомендованный в книге «Практические общие Лиспы».
- Не предварительно упакован, но SLIME превращает Emacs в общую среду Lisp IDE и содержит руководство пользователя, которое поможет вам начать работу. Требуется отдельная реализация Common Lisp.
Общие реализации Lisp
В этом разделе перечислены некоторые общие реализации CL и их руководства. Если не указано иное, это реализация программного обеспечения. См. Также список бесплатных программ Clic's Common Lisp и список коммерческих реализаций Common Lisp в Википедии .
- Allegro Common Lisp (ACL) и руководство пользователя . Коммерческий, но имеет бесплатное Express Edition и учебные видеоролики на Youtube .
- CLISP и руководства .
- Clozure Common Lisp (CCL) и руководство .
- Университет Carnegie Mellon Common Lisp (CMUCL) имеет справочную и другую полезную страницу информации .
- Embeddable Common Lisp (ECL) и руководство .
- LispWorks и руководство . Коммерческий, но имеет личную версию с некоторыми ограничениями .
- Steel Bank Common Lisp (SBCL) и руководство .
- Scieneer Common Lisp (SCL) и руководство - это коммерческая реализация Linux и Unix, но имеет неограниченную бесплатную версию для оценки и некоммерческого использования .