Common Lisp permette al programmatore di scrivere dei «commenti» che il computer ignora.
I commenti su una sola riga iniziano con uno o più punti e virgola (;) e, occasionalmente, potresti vedere quanto segue:
(code...) ; => value
Qui il commento serve a indicare quale valore viene restituito da Common Lisp dopo l'esecuzione del codice su quella riga.
È idiomatico usare un solo punto e virgola per un commento breve alla fine di una riga, due per un commento più lungo sopra una sezione di codice, tre per un commento lungo che descrive qualcosa come una funzione e quattro per un commento come un'intestazione in cima a un file sorgente.
Tutti gli oggetti di Common Lisp sono o «atomi» (valori singoli e indivisibili) o «cons» (costruiti dalla funzione di costruzione «cons»).
Un cons è formato da due parti: il primo elemento e il resto degli elementi.
Per ragioni storiche queste due parti si chiamano car e cdr.
Quando questi cons vengono valutati come codice, il primo elemento (car) rappresenta la funzione che viene chiamata, mentre il resto degli elementi
(cdr) rappresenta gli argomenti di quella funzione:
(<function> <arg1> <arg2> ... <argN>)
; ^ car ^ | ^ cdr ^
Tutto il codice di Common Lisp è fatto di S-Expressions (Symbolic Expressions). Per brevità vengono chiamate sexpr. Ogni sexpr è un atomo o un cons. Quando le S-Expressions vengono valutate, restituiscono automaticamente un valore che prende il posto dell'espressione. Quando scrivi le tue funzioni (usando defun), l'ultimo valore all'interno del corpo della defun viene restituito automaticamente:
;; Defining a new function
(defun gimme-foo () 'foo)
;; Calling the function as an S-Expression
(gimme-foo) ; => FOO
I simboli in Common Lisp sono valori speciali che possono puntare ad altri valori o, nel caso delle keywords, a se stessi. Quando Lisp valuta i simboli, questi vengono sostituiti con i valori a cui puntano:
foo ; => <whatever-foo-points-to>
:foo ; => :FOO
Nota che le keywords sono indicate da un due punti iniziale (:).
Il quoting, cioè l'aggiunta di ' prima di un S-expression, dice a Lisp di non valutare quell'espressione.
Quotando 'foo nel nostro esempio con defun, abbiamo evitato che Lisp tentasse di cercare (senza trovarlo) ciò a cui FOO doveva puntare, restituendo invece il valore FOO stesso.
Se FOO non è stato definito da nessuna parte nel programma:
foo ; => <ERROR! Lisp doesn't know what foo points to!>
'foo ; => FOO
Per ora, puoi considerarlo semplicemente come un modo per restituire simboli da una funzione, ma torneremo sul quoting ed esploreremo ulteriormente le sue implicazioni nei prossimi esercizi sui concetti.
Tu! Sì, proprio tu, coraggioso programmatore Lisp! Lenny l'alieno Lisp ha bisogno del tuo aiuto! Lenny vuole andare a passare il tempo con tutti gli altri alieni Lisp, ma i genitori vogliono che prima metta in ordine la stanza.
Il problema è che Lenny riesce a malapena a vedere il pavimento! Lenny non sa distinguere gli atomi dai cons, i simboli dalle keyword, i car dai cdr!
Puoi aiutare Lenny a sistemare questo disordine? Non dimenticare le tue parentesi, ti serviranno!
Prima di iniziare, Lenny ha bisogno di ripassare come sono fatti i simboli e le keyword: è un po' che non mette in ordine... Aiuta Lenny definendo due funzioni: lennys-favorite-food, che si valuta in un simbolo, e lennys-secret-keyword, che si valuta in una keyword. Per esempio:
(lennys-favorite-food) ; => LASAGNA
(lennys-secret-keyword) ; => :ALIENS-ARE-REAL
Nota che puoi restituire qualsiasi simbolo o keyword tu voglia (se non sei un fan delle lasagne o non credi negli alieni).
Dopo aver ripassato simboli e keyword, è il momento di pulire! Per fare ordine tra tutte le S-Expression sparse per la stanza, Lenny ha bisogno di aiuto per capire cosa è un cons e cosa è un atomo. Puoi aiutare implementando due funzioni, is-an-atom-p e is-a-cons-p:
(is-an-atom-p 'one-thing) ; => T
(is-an-atom-p '(two things)) ; => NIL
(is-a-cons-p 'one-thing) ; => NIL
(is-a-cons-p '(two things)) ; => T
Per questa sezione, ci sono diverse funzioni predefinite di Lisp che potrebbero esserti utili. Inoltre, per ora, puoi semplicemente considerare T come vero e NIL come falso.
Infine, i cons di Lenny sono troppo ingombranti per essere riposti in modo ordinato, quindi vanno divisi in parti più piccole. Puoi aiutare definendo altre due funzioni per suddividere i cons (first-thing e rest-of-it)?
(first-thing '(first second third)) ; => FIRST
(rest-of-it '(first second third)) ; => (SECOND THIRD)
Anche qui, alcune funzioni predefinite di Common Lisp potrebbero tornare utili.
Iscriviti a Exercism per imparare e padroneggiare Common Lisp con 27 concetti92 esercizi e il mentoring di persone reali, tutto gratis.