Lisp, abbreviazione di "LISt Processing", è una famiglia di linguaggi di programmazione che condividono una sintassi distintiva basata su parentesi, principalmente incentrata sulla manipolazione di simboli e liste. È uno dei linguaggi di programmazione di alto livello più antichi, originariamente inventato alla fine degli anni '50, e si è evoluto significativamente nel corso dei decenni. Lisp è particolarmente noto per le sue potenti caratteristiche come il typing dinamico, la gestione automatica della memoria e le funzioni di prima classe, rendendolo adatto per la ricerca sull'IA, il calcolo simbolico e il prototipazione rapida.
Lisp è stato creato da John McCarthy nel 1958 come notazione matematica per programmi informatici e come mezzo pratico per implementare l'IA. Il linguaggio è derivato dal calcolo lambda, un sistema formale nella logica matematica e nella scienza informatica. La prima implementazione è stata condotta sull'IBM 704, e subito dopo sono emersi numerosi dialetti, ognuno dei quali ha aggiunto le proprie caratteristiche e complessità.
Nel corso del tempo sono emersi diversi dialetti notevoli di Lisp, tra cui Common Lisp e Scheme. Common Lisp è stato standardizzato negli anni '80 per unificare vari dialetti, mentre Scheme, che enfatizza la programmazione funzionale e il minimalismo, ha guadagnato popolarità nel mondo accademico. Le influenze di Lisp possono essere viste in molti linguaggi di programmazione moderni, specialmente in quelli che supportano paradigmi di programmazione funzionale, come Clojure, Racket e persino linguaggi come Python e Ruby.
Oggi, Lisp non è tra i linguaggi di programmazione più popolari, ma rimane influente, in particolare nella ricerca, nell'IA e nell'istruzione. La comunità sviluppa attivamente nuovi dialetti come Clojure, che gira sulla Java Virtual Machine (JVM) e si concentra sulla programmazione concorrente.
Lisp utilizza una sintassi unica che impiega parentesi per denotare espressioni, con il codice rappresentato in espressioni simboliche (S-espressioni). Ad esempio:
(+ 1 2)
Questa espressione rappresenta l'addizione di 1 e 2.
Le funzioni in Lisp possono essere passate come argomenti, restituite da altre funzioni e assegnate a variabili:
(defun square (x) (* x x))
(mapcar #'square '(1 2 3 4)) ; restituisce (1 4 9 16)
Lisp è dinamicamente tipizzato, consentendo alle variabili di contenere valori di qualsiasi tipo di dato senza dichiarazione preventiva:
(setq x 10) ; x è ora un numero
(setq x "hello") ; x è ora una stringa
Lisp presenta potenti sistemi di macro che consentono agli sviluppatori di creare costrutti sintattici personalizzati:
(defmacro when (condition &body body)
`(if ,condition
(progn ,@body))
)
Le forme if
e cond
facilitano il controllo del flusso in Lisp:
(if (> x 0)
(print "Positivo")
(print "Non positivo"))
Lisp tratta le liste come strutture dati fondamentali:
(setq my-list '(1 2 3 4))
(car my-list) ; restituisce 1
(cdr my-list) ; restituisce (2 3 4)
Le funzioni sono definite utilizzando il costrutto defun
:
(defun factorial (n)
(if (= n 0)
1
(* n (factorial (- n 1)))))
Common Lisp include un sistema orientato agli oggetti noto come 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 "Ciao, mi chiamo ~A e ho ~A anni."
(person-name p) (person-age p)))
Lisp fornisce un sofisticato meccanismo di gestione degli errori utilizzando handler-case
:
(handler-case
(/ 1 0)
(division-by-zero () (print "Catturato errore di divisione per zero!")))
Le continuazioni sono supportate in alcuni dialetti, consentendo al programma di salvare e ripristinare stati di esecuzione:
(call-with-current-continuation
(lambda (k)
(k 10)))
Diversi Ambienti di Sviluppo Integrati (IDE) e compilatori si rivolgono alla programmazione Lisp. Le scelte popolari includono:
Per costruire un progetto Lisp, di solito si crea un file con estensione ".lisp" o ".lsp". Utilizzando SBCL, un flusso di lavoro tipico può comportare il caricamento del progetto dal REPL:
(load "my-project.lisp")
Per i progetti che utilizzano Quicklisp, un gestore di librerie, le dipendenze possono essere facilmente gestite e caricate.
Lisp è particolarmente noto per le sue applicazioni nell'intelligenza artificiale, nel calcolo simbolico e nell'accademia, ma trova anche utilizzi in:
Lisp è spesso confrontato con:
La traduzione da Lisp ad altri linguaggi viene spesso effettuata utilizzando strumenti di traduzione da sorgente a sorgente. Ad esempio, esistono i seguenti strumenti:
Ognuno di questi strumenti fornisce mappature specifiche che garantiscono che le funzionalità fondamentali di Lisp possano essere rappresentate efficacemente nei linguaggi di destinazione. Per traduzioni più complesse, potrebbe essere necessaria una rifattorizzazione manuale, specialmente per il codice pesantemente ottimizzato con macro.