Lisp, skrót od "LISt Processing", to rodzina języków programowania, które dzielą charakterystyczną składnię opartą na nawiasach, skoncentrowaną głównie na manipulacji symbolami i listami. Jest jednym z najstarszych języków programowania wysokiego poziomu, pierwotnie wynalezionym pod koniec lat 50. XX wieku, i znacznie ewoluował na przestrzeni dziesięcioleci. Lisp jest szczególnie znany ze swoich potężnych funkcji, takich jak dynamiczne typowanie, zbieranie śmieci i funkcje pierwszej klasy, co czyni go odpowiednim do badań nad sztuczną inteligencją, obliczeń symbolicznych i szybkiego prototypowania.
Lisp został stworzony przez Johna McCarthy'ego w 1958 roku jako notacja matematyczna dla programów komputerowych oraz jako praktyczny sposób wdrażania sztucznej inteligencji. Język wywodzi się z rachunku lambda, formalnego systemu w logice matematycznej i informatyce. Pierwsza implementacja miała miejsce na IBM 704, a wkrótce potem pojawiło się wiele dialektów, z których każdy dodawał swoje własne cechy i złożoności.
Na przestrzeni lat pojawiło się kilka znaczących dialektów Lispa, w tym Common Lisp i Scheme. Common Lisp został ustandaryzowany w latach 80. XX wieku, aby zjednoczyć różne dialekty, podczas gdy Scheme, który kładzie nacisk na programowanie funkcyjne i minimalizm, zyskał popularność w środowisku akademickim. Wpływy Lispa można dostrzec w wielu nowoczesnych językach programowania, szczególnie tych, które wspierają paradygmaty programowania funkcyjnego, takich jak Clojure, Racket, a nawet języki takie jak Python i Ruby.
Dziś Lisp nie jest jednym z najpopularniejszych języków programowania, ale pozostaje wpływowy, szczególnie w badaniach, sztucznej inteligencji i edukacji. Społeczność aktywnie rozwija nowsze dialekty, takie jak Clojure, który działa na Java Virtual Machine (JVM) i koncentruje się na programowaniu współbieżnym.
Lisp stosuje unikalną składnię z użyciem nawiasów do oznaczania wyrażeń, przy czym kod reprezentowany jest w wyrażeniach symbolicznych (S-wyrażeniach). Na przykład:
(+ 1 2)
To wyrażenie reprezentuje dodawanie 1 i 2.
Funkcje w Lispie mogą być przekazywane jako argumenty, zwracane z innych funkcji i przypisywane do zmiennych:
(defun square (x) (* x x))
(mapcar #'square '(1 2 3 4)) ; zwraca (1 4 9 16)
Lisp jest dynamicznie typowany, co pozwala zmiennym przechowywać wartości dowolnego typu danych bez wcześniejszej deklaracji:
(setq x 10) ; x jest teraz liczbą
(setq x "hello") ; x jest teraz ciągiem
Lisp oferuje potężne systemy makr, które pozwalają programistom tworzyć niestandardowe konstrukcje składniowe:
(defmacro when (condition &body body)
`(if ,condition
(progn ,@body))
)
Formy if
i cond
ułatwiają kontrolę przepływu w Lispie:
(if (> x 0)
(print "Pozytywna")
(print "Niepozytywna"))
Lisp traktuje listy jako podstawowe struktury danych:
(setq my-list '(1 2 3 4))
(car my-list) ; zwraca 1
(cdr my-list) ; zwraca (2 3 4)
Funkcje definiuje się za pomocą konstrukcji defun
:
(defun factorial (n)
(if (= n 0)
1
(* n (factorial (- n 1)))))
Common Lisp zawiera system obiektowy znany jako Common Lisp Object System (CLOS):
(defclass person ()
((name :initarg :name :accessor person-name)
(age :initarg :age :accessor person-age)))
(defmethod say-hello ((p person))
(format t "Cześć, nazywam się ~A i mam ~A lat."
(person-name p) (person-age p)))
Lisp zapewnia zaawansowany mechanizm obsługi błędów za pomocą handler-case
:
(handler-case
(/ 1 0)
(division-by-zero () (print "Złapano błąd dzielenia przez zero!")))
Niektóre dialekty wspierają kontynuacje, co pozwala programowi na zapisywanie i przywracanie stanów wykonania:
(call-with-current-continuation
(lambda (k)
(k 10)))
Kilka Zintegrowanych Środowisk Programistycznych (IDE) i kompilatorów obsługuje programowanie w Lispie. Popularne wybory to:
Aby zbudować projekt w Lispie, zazwyczaj tworzysz plik z rozszerzeniem ".lisp" lub ".lsp". Używając SBCL, typowy przepływ pracy może obejmować załadowanie projektu z REPL:
(load "my-project.lisp")
Dla projektów korzystających z Quicklisp, menedżera bibliotek, zależności można łatwo zarządzać i ładować.
Lisp jest szczególnie znany ze swoich zastosowań w sztucznej inteligencji, obliczeniach symbolicznych i akademickich, ale znajduje również zastosowanie w:
Lisp często porównywany jest do:
Tłumaczenie z Lispa na inne języki często odbywa się za pomocą narzędzi do tłumaczenia z kodu źródłowego na kod źródłowy. Na przykład istnieją następujące narzędzia:
Każde z tych narzędzi zapewnia specyficzne mapowania, które zapewniają, że podstawowe funkcjonalności Lispa mogą być skutecznie reprezentowane w językach docelowych. W przypadku bardziej złożonych tłumaczeń może być konieczne ręczne refaktoryzowanie, szczególnie w przypadku kodu mocno zoptymalizowanego za pomocą makr.