Vanlig lisp - Common Lisp
Paradigm | Multi-paradigm : procedurellt , funktionellt , objektorienterat , meta , reflekterande , generiskt |
---|---|
Familj | Läspa |
Designad av | Scott Fahlman , Richard P. Gabriel , David A. Moon , Kent Pitman , Guy Steele , Dan Weinreb |
Utvecklare | ANSI X3J13 kommitté |
Första gången dök upp | |
Skrivdisciplin | Dynamisk , stark |
Omfattning | Lexikal, valfritt dynamisk |
OS | Plattformsoberoende |
Filnamnstillägg | .lisp, .lsp, .l, .cl, .fasl |
Hemsida | |
Stora implementeringar | |
Allegro CL , ABCL , CLISP , Clozure CL , CMUCL , ECL , GCL , LispWorks , Scieneer CL , SBCL , Symbolics Common Lisp | |
Dialekter | |
CLtL1, CLtL2, ANSI Common Lisp | |
Påverkad av | |
Lisp , Lisp Machine Lisp , Maclisp , Scheme , Interlisp | |
Påverkad | |
Clojure , Dylan , Emacs Lisp , EuLisp , ISLISP , *Lisp , AutoLisp , Julia , Moose , R , SKILL , SubL |
Common Lisp ( CL ) är en dialekt av programmeringsspråket Lisp , publicerad i ANSI- standarddokumentet ANSI INCITS 226-1994 (S20018) (tidigare X3.226-1994 (R1999) ). Den Common Lisp HyperSpec , en hyperlänk HTML version, har hämtats från ANSI Common Lisp standard.
Common Lisp -språket utvecklades som en standardiserad och förbättrad efterträdare av Maclisp . I början av 1980-talet arbetade flera grupper redan med olika efterträdare till MacLisp: Lisp Machine Lisp (aka ZetaLisp), Spice Lisp , NIL och S-1 Lisp . Common Lisp försökte förena, standardisera och utöka funktionerna i dessa MacLisp -dialekter. Common Lisp är inte ett genomförande, utan snarare en språkspecifikation . Flera implementeringar av Common Lisp-standarden finns tillgängliga, inklusive gratis programvara med öppen källkod och egna produkter. Common Lisp är ett allmänt ändamål, multi-paradigm programmeringsspråk . Den stöder en kombination av procedurella , funktionella och objektorienterade programmeringsparadigm . Som ett dynamiskt programmeringsspråk underlättar det evolutionär och inkrementell mjukvaruutveckling , med iterativ sammanställning till effektiva körtidsprogram. Denna inkrementella utveckling sker ofta interaktivt utan att avbryta den körande applikationen.
Den stöder också valfri typkommentering och gjutning, som kan läggas till vid behov vid senare profilering och optimeringssteg, så att kompilatorn kan generera mer effektiv kod. Till exempel fixnum
kan hålla ett oboxat heltal i ett intervall som stöds av hårdvaran och implementeringen, vilket möjliggör effektivare aritmetik än på stora heltal eller godtyckliga precisionstyper. På samma sätt kan kompilatorn per modul eller per funktion få veta vilken typ av säkerhetsnivå som önskas med hjälp av optimera deklarationer.
Common Lisp innehåller CLOS , ett objektsystem som stöder multimetoder och metodkombinationer. Det implementeras ofta med ett Metaobject -protokoll .
Common Lisp kan utökas med standardfunktioner som Lisp -makron (kodomvandlingar) och läsarmakron (inmatningsparrar för tecken).
Common Lisp ger delvis bakåtkompatibilitet med Maclisp och John McCarthys ursprungliga Lisp . Detta gör att äldre Lisp -programvara kan portas till Common Lisp.
Arbetet med Common Lisp startade 1981 efter ett initiativ av ARPA -chefen Bob Engelmore för att utveckla en gemensam standard för Lisp -dialekt. Mycket av den ursprungliga språkdesignen gjordes via elektronisk post. 1982 gav Guy L. Steele Jr. den första översikten över Common Lisp vid ACM -symposiet 1982 om LISP och funktionell programmering.
Den första språkdokumentationen publicerades 1984 som Common Lisp the Language (känd som CLtL1), första upplagan. En andra upplaga (känd som CLtL2), publicerad 1990, införlivade många ändringar av språket som gjordes under ANSI Common Lisp -standardiseringsprocessen: utökad LOOP -syntax, Common Lisp Object System, Condition System för felhantering, ett gränssnitt till snygg skrivare och mycket mer. Men CLtL2 beskriver inte den slutliga standarden för ANSI Common Lisp och är därför ingen dokumentation av ANSI Common Lisp. Den slutliga ANSI Common Lisp -standarden publicerades sedan 1994. Sedan dess har ingen uppdatering av standarden publicerats. Olika tillägg och förbättringar av Common Lisp (exempel är Unicode, Concurrency, CLOS-based IO) har tillhandahållits av implementeringar och bibliotek.
Common Lisp är en dialekt av Lisp. Den använder S-uttryck för att beteckna både kod och datastruktur. Funktionsanrop, makroformulär och specialformulär skrivs som listor, med operatörens namn först, som i dessa exempel:
(+ 2 2) ; adds 2 and 2, yielding 4. The function's name is '+'. Lisp has no operators as such.
(defvar *x*) ; Ensures that a variable *x* exists,
; without giving it a value. The asterisks are part of
; the name, by convention denoting a special (global) variable.
; The symbol *x* is also hereby endowed with the property that
; subsequent bindings of it are dynamic, rather than lexical.
(setf *x* 42.1) ; Sets the variable *x* to the floating-point value 42.1
;; Define a function that squares a number:
(defun square (x)
(* x x))
;; Execute the function:
(square 3) ; Returns 9
;; The 'let' construct creates a scope for local variables. Here
;; the variable 'a' is bound to 6 and the variable 'b' is bound
;; to 4. Inside the 'let' is a 'body', where the last computed value is returned.
;; Here the result of adding a and b is returned from the 'let' expression.
;; The variables a and b have lexical scope, unless the symbols have been
;; marked as special variables (for instance by a prior DEFVAR).
(let ((a 6)
(b 4))
(+ a b)) ; returns 10
Common Lisp har många datatyper .
Skalära typer
Taltyper inkluderar heltal , förhållanden , flyttal och komplexa tal . Common Lisp använder bignums för att representera numeriska värden av godtycklig storlek och precision. Förhållandetypen representerar fraktioner exakt, en möjlighet som inte är tillgänglig på många språk. Common Lisp tvingar automatiskt till numeriska värden bland dessa typer efter behov.
Den gemensamma Lisp teckentypen är inte begränsat till ASCII tecken. De flesta moderna implementeringar tillåter Unicode -tecken.
Den symbol typen är gemensamt för Lisp språk, men i stort sett okända utanför dem. En symbol är ett unikt, namngivet dataobjekt med flera delar: namn, värde, funktion, egenskapslista och paket. Av dessa är värdecellen och funktionscellen de viktigaste. Symboler i Lisp används ofta på samma sätt som identifierare på andra språk: för att hålla värdet på en variabel; men det finns många andra användningsområden. Normalt, när en symbol utvärderas, returneras dess värde. Vissa symboler utvärderar för sig själva, till exempel är alla symboler i nyckelordspaketet självutvärderande. Booleanska värden i Common Lisp representeras av de självutvärderande symbolerna T och NIL. Common Lisp har namnutrymmen för symboler, kallade "paket".
Ett antal funktioner är tillgängliga för avrundning av skalära numeriska värden på olika sätt. Funktionen round
avrundar argumentet till närmaste heltal, med halvvägs fall avrundade till det jämna heltalet. Funktionerna truncate
,, floor
och ceiling
runda mot noll, nedåt respektive uppåt. Alla dessa funktioner returnerar den bortkastade fraktionsdelen som ett sekundärt värde. Till exempel (floor -2.5)
ger −3, 0,5; (ceiling -2.5)
ger −2, −0,5; (round 2.5)
ger 2, 0,5; och (round 3.5)
ger 4, -0,5.
Data struktur
Sekvenstyper i Common Lisp inkluderar listor, vektorer, bitvektorer och strängar. Det finns många operationer som kan fungera på vilken sekvens typ som helst.
värdet. Nackdelar kan också enkelt användas för att implementera träd och andra komplexa datastrukturer; även om det vanligtvis rekommenderas att använda struktur eller klassinstanser istället. Det är också möjligt att skapa cirkulära datastrukturer med nackdelar.Common Lisp stöder flerdimensionella matriser och kan dynamiskt ändra storlek på justerbara matriser om det behövs. Flerdimensionella matriser kan användas för matrismatematik. En vektor är en endimensionell uppsättning. Arrays kan bära vilken typ som helst (även blandade typer i samma array) eller kan specialiseras för att innehålla en specifik typ av medlemmar, som i en vektor av bitar. Vanligtvis stöds endast ett fåtal typer. Många implementeringar kan optimera matrisfunktioner när matrisen som används är typspecialiserad. Två typspecialiserade array-typer är standard: en sträng är en vektor med tecken, medan en bit-vektor är en vektor med bitar .
Hashtabeller lagrar kopplingar mellan dataobjekt. Alla objekt kan användas som nyckel eller värde. Hashtabellerna ändras automatiskt efter behov.
Paket är samlingar av symboler, som främst används för att separera delarna av ett program i namnområden . Ett paket kan exportera vissa symboler och markera dem som en del av ett offentligt gränssnitt. Paket kan använda andra paket.
Strukturer som liknar C -strukturer och Pascal -poster , representerar godtyckliga komplexa datastrukturer med valfritt antal och typ av fält (kallade slots ). Strukturer tillåter enkel arv.
Klasser liknar strukturer, men erbjuder mer dynamiska funktioner och multipelarv. (Se STÄNG ). Klasser har lagts till sent i Common Lisp och det finns en viss konceptuell överlappning med strukturer. Objekt som skapats av klasser kallas Instanser . Ett specialfall är Generic Functions. Generiska funktioner är både funktioner och instanser.
Funktioner
Common Lisp stöder förstklassiga funktioner . Det är till exempel möjligt att skriva funktioner som tar andra funktioner som argument eller returnera funktioner också. Detta gör det möjligt att beskriva mycket generella verksamheter.
Common Lisp-biblioteket är starkt beroende av sådana högre ordningsfunktioner. Till exempel sort
tar funktionen en relationsoperator som ett argument och nyckelfunktionen som ett valfritt sökordsargument. Detta kan användas inte bara för att sortera vilken typ av data som helst, utan också för att sortera datastrukturer enligt en nyckel.
;; Sorts the list using the > and < function as the relational operator.
(sort (list 5 2 6 3 1 4) #'>) ; Returns (6 5 4 3 2 1)
(sort (list 5 2 6 3 1 4) #'<) ; Returns (1 2 3 4 5 6)
;; Sorts the list according to the first element of each sub-list.
(sort (list '(9 A) '(3 B) '(4 C)) #'< :key #'first) ; Returns ((3 B) (4 C) (9 A))
Utvärderingsmodellen för funktioner är mycket enkel. När utvärderaren stöter på ett formulär (f a1 a2...)
förutsätter det att symbolen som heter f är något av följande:
- En speciell operatör (kontrolleras enkelt mot en fast lista)
- En makrooperatör (måste ha definierats tidigare)
- Namnet på en funktion (standard), som antingen kan vara en symbol eller en underform som börjar med symbolen
lambda
.
Om f är namnet på en funktion, utvärderas argumenten a1, a2, ..., an i ordning från vänster till höger, och funktionen hittas och åberopas med de värden som tillhandahålls som parametrar.
Definiera funktioner
Den makrotdefun
definierar funktioner där en definition funktion ger namnet på funktionen, namnen på några argument, och en funktion kropp:
(defun square (x)
(* x x))
Funktionsdefinitioner kan inbegripa kompilatordirektiv , kända som deklarationer , som ger tips till kompilatorn om optimerings inställningar eller de datatyper av argument. De kan också innehålla dokumentationssträngar (docstrings), som Lisp -systemet kan använda för att tillhandahålla interaktiv dokumentation:
(defun square (x)
"Calculates the square of the single-float x."
(declare (single-float x) (optimize (speed 3) (debug 0) (safety 1)))
(the single-float (* x x)))
Anonyma funktioner ( funktionslitteraler ) definieras med lambda
uttryck, t.ex. (lambda (x) (* x x))
för en funktion som kvadrerar dess argument. Lisp programmeringsstil använder ofta högre ordningsfunktioner för vilka det är användbart att tillhandahålla anonyma funktioner som argument.
Lokala funktioner kan definieras med flet
och labels
.
(flet ((square (x)
(* x x)))
(square 3))
Det finns flera andra operatörer relaterade till definition och manipulation av funktioner. Till exempel kan en funktion kompileras med compile
operatören. (Vissa Lisp -system kör funktioner med en tolk som standard om de inte instrueras att kompilera; andra kompilerar varje funktion).
Definiera generiska funktioner och metoder
Makrot defgeneric
definierar generiska funktioner . Generiska funktioner är en samling metoder . Makrot defmethod
definierar metoder.
Metoder kan specialisera sina parametrar över CLOS -standardklasser , systemklasser , strukturklasser eller enskilda objekt. För många typer finns motsvarande systemklasser .
När en generisk funktion anropas, avgör multipelsändning den effektiva metoden att använda.
(defgeneric add (a b))
(defmethod add ((a number) (b number))
(+ a b))
(defmethod add ((a vector) (b number))
(map 'vector (lambda (n) (+ n b)) a))
(defmethod add ((a vector) (b vector))
(map 'vector #'+ a b))
(defmethod add ((a string) (b string))
(concatenate 'string a b))
(add 2 3) ; returns 5
(add #(1 2 3 4) 7) ; returns #(8 9 10 11)
(add #(1 2 3 4) #(4 3 2 1)) ; returns #(5 5 5 5)
(add "COMMON " "LISP") ; returns "COMMON LISP"
Generiska funktioner är också en förstklassig datatyp . Det finns många fler funktioner för generiska funktioner och metoder än beskrivet ovan.
Funktionsnamnutrymmet
Namnutrymmet för funktionsnamn är separat från namnutrymmet för datavariabler. Detta är en viktig skillnad mellan Common Lisp och Scheme . För Common Lisp, operatörer som definierar namn i funktionen namespace inkluderar defun
, flet
, labels
, defmethod
och defgeneric
.
För att överföra en funktion med namn som argument till en annan funktion måste man använda function
specialoperatören, vanligen förkortad som #'
. Det första sort
exemplet ovan hänvisar till funktionen som namnges av symbolen >
i funktionsnamnutrymmet, med koden #'>
. Omvänt, för att anropa en funktion som skickas på ett sådant sätt, skulle man använda funcall
operatören på argumentet.
Schemas utvärderingsmodell är enklare: det finns bara ett namnutrymme och alla positioner i formuläret utvärderas (i valfri ordning) - inte bara argumenten. Kod skriven på en dialekt är därför ibland förvirrande för programmerare som är mer erfarna inom den andra. Till exempel gillar många vanliga Lisp -programmerare att använda beskrivande variabelnamn som lista eller sträng som kan orsaka problem i Scheme, eftersom de lokalt skulle skugga funktionsnamn.
Om ett separat namnutrymme för funktioner är en fördel är en källa till tvist i Lisp -gemenskapen. Det brukar kallas Lisp-1 vs Lisp-2-debatten . Lisp-1 hänvisar till Schemes modell och Lisp-2 hänvisar till Common Lisps modell. Dessa namn myntades i ett papper från 1988 av Richard P. Gabriel och Kent Pitman , som utförligt jämför de två tillvägagångssätten.
Flera returvärden
Common Lisp stöder konceptet med flera värden , där alla uttryck alltid har ett enda primärt värde , men det kan också ha valfritt antal sekundära värden , som kan tas emot och inspekteras av intresserade uppringare. Detta koncept skiljer sig från att returnera ett listvärde, eftersom de sekundära värdena är helt valfria och skickas via en dedikerad sidokanal. Detta innebär att uppringare kan vara helt omedvetna om att de sekundära värdena finns där om de inte behöver dem, och det gör det bekvämt att använda mekanismen för att kommunicera information som ibland är användbar, men inte alltid nödvändig. Till exempel,
- Den
TRUNCATE
funktion avrundar det angivna talet till ett heltal mot noll. Det returnerar emellertid också en återstod som ett sekundärt värde, vilket gör det mycket enkelt att avgöra vilket värde som avkortades. Det stöder också en valfri divisor -parameter, som kan användas för att utföra euklidisk division trivialt:
(let ((x 1266778)
(y 458))
(multiple-value-bind (quotient remainder)
(truncate x y)
(format nil "~A divided by ~A is ~A remainder ~A" x y quotient remainder)))
;;;; => "1266778 divided by 458 is 2765 remainder 408"
-
GETHASH
returnerar värdet på en nyckel i en associerad karta , eller standardvärdet annars, och en sekundär boolean som anger om värdet hittades. Således kan kod som inte bryr sig om värdet hittades eller tillhandahållits som standard helt enkelt använda det som det är, men när sådan skillnad är viktig kan den inspektera den sekundära boolean och reagera på lämpligt sätt. Båda användningsfallen stöds av samma samtal och varken belastas eller begränsas i onödan av den andra. Att ha den här funktionen på språknivå tar bort behovet av att kontrollera om det finns en nyckel eller jämföra den med null som skulle göras på andra språk.
(defun get-answer (library)
(gethash 'answer library 42))
(defun the-answer-1 (library)
(format nil "The answer is ~A" (get-answer library)))
;;;; Returns "The answer is 42" if ANSWER not present in LIBRARY
(defun the-answer-2 (library)
(multiple-value-bind (answer sure-p)
(get-answer library)
(if (not sure-p)
"I don't know"
(format nil "The answer is ~A" answer))))
;;;; Returns "I don't know" if ANSWER not present in LIBRARY
Flera värden stöds av en handfull standardformulär, varav de vanligaste är den MULTIPLE-VALUE-BIND
speciella blanketten för åtkomst till sekundära värden och VALUES
för att returnera flera värden:
(defun magic-eight-ball ()
"Return an outlook prediction, with the probability as a secondary value"
(values "Outlook good" (random 1.0)))
;;;; => "Outlook good"
;;;; => 0.3187
Andra typer
Andra datatyper i Common Lisp inkluderar:
- Sökvägar representerar filer och kataloger i filsystemet . Den gemensamma Lisp -bannamnsfunktionen är mer allmän än de flesta operativsystems filnamnkonventioner, vilket gör att Lisp -program har tillgång till filer i stort sett bärbara över olika system.
- Ingångs- och utgångsströmmarna representerar källor och sänkor av binära eller textdata, såsom de terminala eller öppna filer.
- Common Lisp har en inbyggd pseudo-slumpgenerator (PRNG). Slumpmässiga tillståndsobjekt representerar återanvändbara källor till pseudo-slumpmässiga tal, så att användaren kan seeda PRNG eller få den att spela om en sekvens.
- Villkor är en typ som används för att representera fel, undantag och andra "intressanta" händelser som ett program kan svara på.
- Klasser är förstklassiga objekt , och är själva instanser av klasser som kallas metaobject-klasser ( metaclasses för kort).
- Läsbord är en typ av objekt som styr hur Common Lisp läsare analyserar texten i källkoden. Genom att styra vilken lästabell som används när kod läses in kan programmeraren ändra eller utöka språkets syntax.
Liksom program på många andra programmeringsspråk använder Common Lisp -program namn för att referera till variabler, funktioner och många andra typer av enheter. Namngivna referenser omfattas av tillämpningsområdet.
Föreningen mellan ett namn och den enhet som namnet hänvisar till kallas en bindning.
Omfattning avser den uppsättning omständigheter under vilka ett namn bestäms för att ha en viss bindning.
Bestämmare av omfattning
Omständigheterna som bestämmer omfattningen i Common Lisp inkluderar:
- platsen för en referens i ett uttryck. Om det är den vänstra positionen av en förening, refererar den till en speciell operator eller en makro- eller funktionsbindning, annars till en variabelbindning eller något annat.
- den typ av uttryck som referensen sker i. Till exempel
(go x)
betyder överföringskontroll till etikettx
, medan(print x)
refererar till variabelnx
. Båda omfattningarna avx
kan vara aktiva i samma programtexttext, eftersom tagbody -etiketter finns i ett separat namnutrymme från variabelnamn. En speciell form eller makroform har fullständig kontroll över alla symbolers betydelse i dess syntax. Till exempel, i(defclass x (a b) ())
, en klassdefinition,(a b)
är en lista över basklasser, så dessa namn slås upp i utrymmet med klassnamn ochx
är inte en referens till en befintlig bindning, utan namnet på en ny klass som härleds fråna
ochb
. Dessa fakta kommer enbart ur semantiken idefclass
. Det enda generiska faktumet om detta uttryck är det somdefclass
hänvisar till en makrobindning; allt annat är upp tilldefclass
. - platsen för referensen i programtexten. Till exempel, om en referens till variabel
x
är innesluten i en bindande konstrukt, såsom enlet
som definierar en bindning förx
, då referensen är i tillämpningsområdet som skapas av denna bindning. - för en variabelreferens, oavsett om en variabelsymbol lokalt eller globalt har förklarats som speciell eller inte. Detta avgör om referensen löses inom en lexikal miljö eller i en dynamisk miljö.
- den specifika förekomsten av miljön där referensen är löst. En miljö är en körtidsordbok som kartlägger symboler till bindningar. Varje typ av referens använder sin egen typ av miljö. Hänvisningar till lexikala variabler löses i en lexikal miljö osv. Mer än en miljö kan associeras med samma referens. Till exempel, tack vare rekursion eller användningen av flera trådar, kan flera aktiveringar av samma funktion existera samtidigt. Dessa aktiveringar delar samma programtext, men var och en har sin egen lexikaliska miljöinstans.
För att förstå vad en symbol hänvisar till måste Common Lisp-programmeraren veta vilken typ av referens som uttrycks, vilken typ av omfång den använder om den är en variabel referens (dynamisk kontra lexikal omfattning), och även körningssituationen: i vilken miljö är referensen löst, var infördes bindningen i miljön, etc.
Slag av miljö
Global
Vissa miljöer i Lisp är globalt genomträngande. Till exempel, om en ny typ definieras, är den känd överallt därefter. Hänvisningar till den typen letar upp det i denna globala miljö.
Dynamisk
En typ av miljö i Common Lisp är den dynamiska miljön. Bindningar etablerade i denna miljö har dynamisk omfattning, vilket innebär att en bindning upprättas i början av utförandet av en konstruktion, till exempel ett let
block, och försvinner när den konstruktionen slutfördes: dess livstid är knuten till dynamisk aktivering och avaktivering av ett block. En dynamisk bindning är emellertid inte bara synlig inom det blocket; det är också synligt för alla funktioner som åberopas från det blocket. Denna typ av synlighet kallas obestämd omfattning. Bindningar som uppvisar dynamisk omfattning (livslängd kopplad till aktivering och avaktivering av ett block) och obestämd omfattning (synlig för alla funktioner som anropas från det blocket) sägs ha dynamiskt omfång.
Common Lisp har stöd för dynamiskt omfattande variabler, som också kallas specialvariabler. Vissa andra typer av bindningar är nödvändigtvis också dynamiskt omfattande, till exempel omstart och taggtag. Funktionsbindningar kan inte dynamiskt omfattas med flet
(som endast tillhandahåller funktionsbindningar med lexiskt omfattning), men funktionsobjekt (ett objekt på första nivån i Common Lisp) kan tilldelas dynamiskt omfattande variabler, bundna med let
dynamiskt omfång, kallas sedan med funcall
eller APPLY
.
Dynamiskt omfång är extremt användbart eftersom det lägger till referensklarhet och disciplin till globala variabler . Globala variabler frånsas i datavetenskap som potentiella felkällor, eftersom de kan ge upphov till ad-hoc, dolda kommunikationskanaler mellan moduler som leder till oönskade, överraskande interaktioner.
I Common Lisp beter sig en speciell variabel som bara har en bindning på högsta nivå precis som en global variabel i andra programmeringsspråk. Ett nytt värde kan lagras i det, och det värdet ersätter helt enkelt det som finns i bindningen på översta nivån. Slarvig ersättning av värdet av en global variabel är kärnan i buggar som orsakas av användning av globala variabler. Ett annat sätt att arbeta med en speciell variabel är dock att ge den en ny, lokal bindning inom ett uttryck. Detta kallas ibland för "ombindning" av variabeln. Bindning av en dynamiskt omfattande variabel skapar tillfälligt en ny minnesplats för den variabeln och kopplar namnet till den platsen. Medan denna bindning är i kraft hänvisar alla referenser till den variabeln till den nya bindningen; föregående bindning är dold. När exekveringen av bindningsuttrycket avslutas är den tillfälliga minnesplatsen borta och den gamla bindningen avslöjas, med det ursprungliga värdet intakt. Naturligtvis kan flera dynamiska bindningar för samma variabel kapas.
I Common Lisp -implementeringar som stöder multithreading är dynamiska omfattningar specifika för varje tråd av körning. Sålunda fungerar speciella variabler som en abstraktion för lokal lagring av trådar. Om en tråd gör om en särskild variabel, har denna återbindning ingen effekt på den variabeln i andra trådar. Värdet som lagras i en bindning kan endast hämtas av tråden som skapade bindningen. Om varje tråd binder någon särskild variabel *x*
, *x*
beter sig den som tråd-lokal lagring. Bland trådar som inte återbinds *x*
uppför den sig som en vanlig global: alla dessa trådar hänvisar till samma bindning på högsta nivå av *x*
.
Dynamiska variabler kan användas för att utöka exekveringssammanhanget med ytterligare kontextinformation som implicit överförs från funktion till funktion utan att behöva visas som en extra funktionsparameter. Detta är särskilt användbart när kontrollöverföringen måste passera genom lager av orelaterad kod, som helt enkelt inte kan utökas med extra parametrar för att skicka ytterligare data. En sådan situation kräver vanligtvis en global variabel. Den globala variabeln måste sparas och återställas, så att schemat inte går sönder under rekursion: dynamisk variabelåterbindning tar hand om detta. Och den variabeln måste göras trådlokal (annars måste en stor mutex användas) så att systemet inte bryter under trådar: dynamiska omfattningsimplementeringar kan också ta hand om detta.
I Common Lisp -biblioteket finns det många standard specialvariabler. Till exempel lagras alla standard I/O-strömmar i toppnivåbindningar av välkända specialvariabler. Standardutmatningsströmmen lagras i *standardutgång *.
Antag att en funktion foo skriver till standardutgång:
(defun foo ()
(format t "Hello, world"))
För att fånga dess utmatning i en teckensträng kan * standard-output * bindas till en strängström och kallas:
(with-output-to-string (*standard-output*)
(foo))
-> "Hello, world" ; gathered output returned as a string
Lexikalisk
Common Lisp stöder lexikala miljöer. Formellt har bindningarna i en lexikal miljö lexikal omfattning och kan antingen ha en obestämd omfattning eller dynamisk omfattning, beroende på typen av namnområde. Lexikal omfattning innebär att synligheten fysiskt är begränsad till det block där bindningen etableras. Referenser som inte är textmässigt (dvs lexiskt) inbäddade i det blocket ser helt enkelt inte den bindningen.
Etiketterna i en TAGBODY har lexikal omfattning. Uttrycket (GO X) är felaktigt om det inte är inbäddat i en TAGBODY som innehåller en etikett X. Emellertid försvinner etikettbindningarna när TAGBODY avslutar körningen, eftersom de har dynamisk omfattning. Om det här kodblocket matas in igen genom åberopandet av en lexikal stängning är det ogiltigt för stängningen att försöka överföra kontrollen till en tagg via GO:
(defvar *stashed*) ;; will hold a function
(tagbody
(setf *stashed* (lambda () (go some-label)))
(go end-label) ;; skip the (print "Hello")
some-label
(print "Hello")
end-label)
-> NIL
När TAGBODY körs utvärderar den först setf -formuläret som lagrar en funktion i specialvariabeln *stashed *. Sedan överför (go end-label) kontrollen till slutetiketten och hoppar över koden (skriv ut "Hej"). Eftersom slutetiketten är i slutet av etikettkroppen, avslutas taggkroppen och ger NIL. Antag att den tidigare ihågkomna funktionen nu heter:
(funcall *stashed*) ;; Error!
Denna situation är felaktig. En implementerings svar är ett felvillkor som innehåller meddelandet "GO: tagbody for tag SOME-LABEL has already been left". Funktionen försökte utvärdera (go some-label), som är lexiskt inbäddat i taggkroppen, och löser sig till etiketten. Tagkroppen körs dock inte (dess omfattning har upphört), och därför kan kontrollöverföringen inte ske.
Lokala funktionsbindningar i Lisp har lexikal omfattning och variabla bindningar har också lexikal omfattning som standard. Till skillnad från GO -etiketter har båda dessa obegränsad omfattning. När en lexikal funktion eller variabel bindning är etablerad, fortsätter denna bindning att existera så länge som referenser till den är möjliga, även efter den konstruktion som fastställde att bindningen har upphört. Hänvisningar till lexikaliska variabler och funktioner efter avslutandet av deras uppbyggande konstruktion är möjliga tack vare lexikaliska stängningar .
Lexikal bindning är standardbindningsläget för vanliga Lisp -variabler. För en enskild symbol kan den växlas till dynamiskt omfång, antingen genom en lokal deklaration, med en global deklaration. Det senare kan inträffa implicit genom användning av en konstruktion som DEFVAR eller DEFPARAMETER. Det är en viktig konvention i Common Lisp -programmering att speciella (dvs dynamiskt omfattande) variabler har namn som börjar och slutar med en asterisk -sigil *
i det som kallas " hörselskyddskonventionen ". Om den följs skapar denna konvention effektivt ett separat namnutrymme för speciella variabler, så att variabler som är avsedda att vara lexikaliska inte av misstag görs speciella.
Lexiskt omfång är användbart av flera skäl.
För det första kan referenser till variabler och funktioner sammanställas till effektiv maskinkod, eftersom driftstidsmiljöstrukturen är relativt enkel. I många fall kan den optimeras för att stapla lagring, så att öppna och stänga lexikalomfattningar har minimala omkostnader. Även i de fall där fullständiga stängningar måste genereras är tillgången till stängningens miljö fortfarande effektiv; vanligtvis blir varje variabel en förskjutning till en vektor av bindningar, och så blir en variabelreferens till en enkel laddnings- eller lagringsinstruktion med ett bas-plus-offset- adresseringsläge .
För det andra ger lexikal omfattning (kombinerat med obestämd omfattning) upphov till den lexikaliska stängningen , vilket i sin tur skapar ett helt paradigm av programmering centrerad kring användningen av funktioner som förstklassiga objekt, som ligger till grund för funktionell programmering.
För det tredje, kanske viktigast av allt, även om lexikala stängningar inte utnyttjas, isolerar användningen av lexikal omfattning programmoduler från oönskade interaktioner. På grund av sin begränsade synlighet är lexikala variabler privata. Om en modul A binder en lexikal variabel X och anropar en annan modul B, kommer hänvisningar till X i B inte av misstag att lösas till X bunden i A. B har helt enkelt ingen tillgång till X. För situationer där disciplinerade interaktioner genom en variabel är önskvärt, Common Lisp ger speciella variabler. Speciella variabler gör det möjligt för en modul A att skapa en bindning för en variabel X som är synlig för en annan modul B, uppringd från A. Att kunna göra detta är en fördel, och att kunna förhindra att det händer är också en fördel; följaktligen stöder Common Lisp både lexikal och dynamisk omfattning .
Ett makro i Lisp liknar ytligt en funktion vid användning. Istället för att representera ett uttryck som utvärderas representerar det emellertid en transformation av programmets källkod. Makrot får källan det omger som argument, binder dem till dess parametrar och beräknar en ny källform. Denna nya form kan också använda ett makro. Makroexpansionen upprepas tills den nya källformen inte använder ett makro. Den slutliga beräknade formen är källkoden som körs vid körning.
Typiska användningsområden för makron i Lisp:
- nya kontrollstrukturer (exempel: looping -konstruktioner, förgreningskonstruktioner)
- omfattande och bindande konstruktioner
- förenklad syntax för komplex och upprepad källkod
- definiera formulär på högsta nivå med kompileringstidseffekter
- datadriven programmering
- inbäddade domänspecifika språk (exempel: SQL , HTML , Prolog )
- implicita finaliseringsformulär
Olika vanliga Common Lisp -funktioner måste också implementeras som makron, till exempel:
- standardabstraktionen
setf
, för att tillåta anpassade kompileringstidsutvidgningar av tilldelnings-/åtkomstoperatörer -
with-accessors
,with-slots
,with-open-file
Och andra liknandeWITH
makron - Beroende på implementering,
if
ellercond
är ett makro byggt på den andra, den särskilda operatören;when
ochunless
består av makron - Det kraftfulla
loop
domänspecifika språket
Makron definieras av defmacro -makrot . Den speciella operatörs macrolet tillåter definitionen av lokala (lexikalt scoped) makron. Det är också möjligt att definiera makron för symboler med hjälp av definiera-symbol-makro och symbol-makrolett .
Paul Grahams bok On Lisp beskriver användningen av makron i Common Lisp i detalj. Doug Hoytes bok Let Over Lambda förlänger diskussionen om makron och hävdar "Makron är den enskilt största fördelen som lisp har som programmeringsspråk och den enskilt största fördelen med alla programmeringsspråk." Hoyte ger flera exempel på iterativ utveckling av makron.
Exempel med hjälp av ett makro för att definiera en ny kontrollstruktur
Makron gör att Lisp -programmerare kan skapa nya syntaktiska former på språket. En typisk användning är att skapa nya kontrollstrukturer. Exempelmakrot tillhandahåller en until
looping -konstruktion. Syntaxen är:
(until test form*)
Makrodefinitionen för tills :
(defmacro until (test &body body)
(let ((start-tag (gensym "START"))
(end-tag (gensym "END")))
`(tagbody ,start-tag
(when ,test (go ,end-tag))
(progn ,@body)
(go ,start-tag)
,end-tag)))
tagbody är en primitiv Common Lisp -specialoperatör som ger möjlighet att namnge taggar och använda go -formuläret för att hoppa till dessa taggar. Backcitatet ` ger en notation som tillhandahåller kodmallar, där värdet på formulär som föregås av ett kommatecken fylls i. Formulär som föregås av komma och at-sign splitsas in. Tagbody-formuläret testar slutvillkoret. Om villkoret är sant hoppar det till sluttaggen. Annars körs den angivna kroppskoden och sedan hoppar den till starttaggen.
Ett exempel på att använda ovanstående tills makro:
(until (= (random 10) 0)
(write-line "Hello"))
Koden kan utökas med funktionen macroexpand-1 . Expansionen för exemplet ovan ser ut så här:
(TAGBODY
#:START1136
(WHEN (ZEROP (RANDOM 10))
(GO #:END1137))
(PROGN (WRITE-LINE "hello"))
(GO #:START1136)
#:END1137)
Vid makro expansionen värdet av variabeln testet är (= (slumpvis 10) 0) och värdet av variabeln kroppen är ((write-line "Hello")) . Kroppen är en lista över former.
Symboler är vanligtvis automatiskt uppskalade. Expansionen använder TAGBODY med två etiketter. Symbolerna för dessa etiketter beräknas av GENSYM och interneras inte i något paket. Two go -formulär använder dessa taggar för att hoppa till. Eftersom tagbody är en primitiv operatör i Common Lisp (och inte ett makro), kommer den inte att expanderas till något annat. Den utökade formen använder när -makrot, som också kommer att utökas. Att helt expandera en källform kallas kodvandring .
I den helt expanderade ( promenerade ) formen ersätts när -formen med den primitiva om :
(TAGBODY
#:START1136
(IF (ZEROP (RANDOM 10))
(PROGN (GO #:END1137))
NIL)
(PROGN (WRITE-LINE "hello"))
(GO #:START1136))
#:END1137)
Alla makron måste utökas innan källkoden som innehåller dem kan utvärderas eller kompileras normalt. Makron kan betraktas som funktioner som accepterar och returnerar S-uttryck- liknande abstrakta syntaxträd , men inte begränsat till dem. Dessa funktioner åberopas inför utvärderaren eller kompilatorn för att producera den slutliga källkoden. Makron är skrivna i normal Common Lisp och kan använda alla tillgängliga Common Lisp (eller tredjeparts) operatörer.
Variabel fångst och skuggning
Vanliga Lisp-makron är kapabla till vad som vanligtvis kallas variabel fångst , där symboler i makroexpansionskroppen sammanfaller med dem i samtalssammanhanget, så att programmeraren kan skapa makron där olika symboler har särskild betydelse. Begreppet variabelinsamling är något vilseledande, eftersom alla namnområden är sårbara för oönskad fångst, inklusive operatörs- och funktionsnamnutrymme, tagbody -etikettnamnutrymme, catch -tag, villkorshanterare och omstartsnamn.
Variabel inspelning kan införa programvarufel. Detta sker på ett av följande två sätt:
- På det första sättet kan en makroexpansion oavsiktligt göra en symbolisk referens som makroförfattaren antog kommer att lösa i ett globalt namnområde, men koden där makrot expanderas ger en lokal, skuggande definition som stjäl den referensen. Låt detta kallas för typ 1 -fångst.
- Det andra sättet, typ 2 -fångst, är precis tvärtom: några av makroens argument är kodbitar som tillhandahålls av makroanroparen, och dessa kodbitar skrivs så att de refererar till omgivande bindningar. Makrot infogar emellertid dessa kodbitar i en expansion som definierar sina egna bindningar som av misstag fångar några av dessa referenser.
Schemadialekten för Lisp tillhandahåller ett makroskrivningssystem som tillhandahåller referensgenomskinlighet som eliminerar båda typerna av inspelningsproblem. Denna typ av makrosystem kallas ibland "hygienisk", särskilt av dess förespråkare (som betraktar makrosystem som inte automatiskt löser detta problem som ohygieniska).
I Common Lisp säkerställs makrohygien på ett av två olika sätt.
Ett tillvägagångssätt är att använda gensyms : garanterade unika symboler som kan användas i en makroexpansion utan hot om fångst. Användningen av gensyms i en makrodefinition är en manuell syssla, men det kan skrivas makron som förenklar instantiering och användning av gensym. Gensyms löser fångst av typ 2 enkelt, men de är inte tillämpliga på typ 1 -fångst på samma sätt, eftersom makroexpansionen inte kan byta namn på de störande symbolerna i den omgivande koden som fångar dess referenser. Gensyms kan användas för att tillhandahålla stabila alias för de globala symboler som makroexpansionen behöver. Makroexpansionen skulle använda dessa hemliga alias snarare än de välkända namnen, så omdefiniering av de välkända namnen skulle inte ha någon dålig effekt på makrot.
Ett annat tillvägagångssätt är att använda paket. Ett makro definierat i sitt eget paket kan helt enkelt använda interna symboler i det paketet i sin expansion. Paketanvändning avser typ 1 och typ 2 fångst.
Paket löser dock inte typ 1 -fångst av referenser till vanliga Common Lisp -funktioner och operatörer. Anledningen är att användningen av paket för att lösa fångstproblem kretsar kring användningen av privata symboler (symboler i ett paket, som inte importeras till, eller på annat sätt görs synliga i andra paket). Medan Common Lisp-bibliotekssymbolerna är externa och ofta importeras till eller görs synliga i användardefinierade paket.
Följande är ett exempel på oönskad fångst i operatörens namnutrymme, som sker i expansionen av ett makro:
;; expansion of UNTIL makes liberal use of DO
(defmacro until (expression &body body)
`(do () (,expression) ,@body))
;; macrolet establishes lexical operator binding for DO
(macrolet ((do (...) ... something else ...))
(until (= (random 10) 0) (write-line "Hello")))
Den until
makro kommer att expandera till en form som samtal do
som är avsett att hänvisa till standard Common Lisp makro do
. Men i detta sammanhang do
kan det ha en helt annan betydelse, så det until
kanske inte fungerar korrekt.
Common Lisp löser problemet med skuggning av standardoperatörer och funktioner genom att förbjuda deras omdefiniering. Eftersom det omdefinierar standardoperatören do
är det föregående faktiskt ett fragment av icke-överensstämmande Common Lisp, som gör det möjligt för implementeringar att diagnostisera och avvisa det.
Det villkoret systemet är ansvarig för undantagshantering i Common Lisp. Det ger villkor , hanterare och omstart . Villkor s är objekt som beskriver en exceptionell situation (till exempel ett fel). Om ett villkor signaleras, söker Common Lisp -systemet efter en hanterare för denna villkorstyp och anropar hanteraren. Det handler kan nu söka efter omstarter och använda en av dessa omstarter för att automatiskt reparera det nuvarande problemet med hjälp av information såsom tillståndet typ och all relevant information som en del av villkoret objektet och anropa lämplig omstartningsfunktion.
Dessa omstarter, om de inte hanteras av kod, kan presenteras för användare (som en del av ett användargränssnitt, till exempel en debugger), så att användaren kan välja och åberopa en av de tillgängliga omstartarna. Eftersom tillståndshanteraren anropas i samband med felet (utan att avveckla stapeln) är fullständig felåterställning möjlig i många fall, där andra undantagshanteringssystem redan skulle ha avslutat den nuvarande rutinen. Själva felsökaren kan också anpassas eller ersättas med den *debugger-hook*
dynamiska variabeln. Kod som finns i avvecklingsskyddsformulär, till exempel slutbehandlare, kommer också att köras vid behov trots undantaget.
I följande exempel (med Symbolics Genera ) användaren försöker öppna en fil i en Lisp funktionstestet anropas från Skriv Eval-Print-LOOP ( REPL ), när filen inte existerar. Lisp -systemet presenterar fyra omstarter. Användaren väljer Retry OPEN med hjälp av ett annat sökvägsnamn och startar ett annat söknamn (lispm-init.lisp istället för lispm-int.lisp). Användarkoden innehåller ingen felhanteringskod. Hela felhanterings- och omstartskoden tillhandahålls av Lisp -systemet, som kan hantera och reparera felet utan att avsluta användarkoden.
Command: (test ">zippy>lispm-int.lisp")
Error: The file was not found.
For lispm:>zippy>lispm-int.lisp.newest
LMFS:OPEN-LOCAL-LMFS-1
Arg 0: #P"lispm:>zippy>lispm-int.lisp.newest"
s-A, <Resume>: Retry OPEN of lispm:>zippy>lispm-int.lisp.newest
s-B: Retry OPEN using a different pathname
s-C, <Abort>: Return to Lisp Top Level in a TELNET server
s-D: Restart process TELNET terminal
-> Retry OPEN using a different pathname
Use what pathname instead [default lispm:>zippy>lispm-int.lisp.newest]:
lispm:>zippy>lispm-init.lisp.newest
...the program continues
Common Lisp innehåller en verktygslåda för objektorienterad programmering , Common Lisp Object System eller CLOS , som är ett av de mest kraftfulla objektsystemen som finns på alla språk. Till exempel förklarar Peter Norvig hur många designmönster som är enklare att implementera på ett dynamiskt språk med funktionerna i CLOS (Multiple Inheritance, Mixins, Multimethods, Metaclasses, Method kombinationer, etc.). Flera tillägg till Common Lisp för objektorienterad programmering har föreslagits inkluderas i ANSI Common Lisp-standarden, men så småningom antogs CLOS som standardobjekt-system för Common Lisp. CLOS är ett dynamiskt objektsystem med flera sändningar och flera arv , och skiljer sig radikalt från OOP -faciliteterna som finns på statiska språk som C ++ eller Java . Som ett dynamiskt objektsystem tillåter CLOS förändringar vid körning av generiska funktioner och klasser. Metoder kan läggas till och tas bort, klasser kan läggas till och omdefinieras, objekt kan uppdateras för klassändringar och klassen av objekt kan ändras.
CLOS har integrerats i ANSI Common Lisp. Generiska funktioner kan användas som vanliga funktioner och är en förstklassig datatyp. Varje CLOS -klass är integrerad i systemet Common Lisp. Många vanliga Lisp -typer har en motsvarande klass. Det finns mer potentiell användning av CLOS för Common Lisp. Specifikationen säger inte om villkor är implementerade med CLOS. Sökvägar och strömmar kan implementeras med CLOS. Dessa ytterligare användningsmöjligheter för CLOS för ANSI Common Lisp är inte en del av standarden. Faktiska Common Lisp -implementeringar använder CLOS för sökvägar, strömmar, input -output, villkor, implementeringen av CLOS själv och mer.
En Lisp-tolk kör direkt Lisp-källkoden som tillhandahålls som Lisp-objekt (listor, symboler, siffror, ...) lästa från s-uttryck. En Lisp -kompilator genererar bytekod eller maskinkod från Lisp -källkoden. Med Common Lisp kan både enskilda Lisp -funktioner kompileras i minnet och sammanställning av hela filer till externt lagrad kompilerad kod ( fasl -filer).
Flera implementeringar av tidigare Lisp -dialekter gav både tolk och kompilator. Tyvärr var semantiken ofta annorlunda. Dessa tidigare Lisps implementerade lexikal scoping i kompilatorn och dynamiskt scoping i tolken. Common Lisp kräver att både tolk och kompilator använder lexikal scoping som standard. Common Lisp -standarden beskriver både tolkens semantik och en kompilator. Kompilatorn kan anropas med funktionen kompilera för enskilda funktioner och använda funktionen sammanställa-fil för filer. Common Lisp tillåter typdeklarationer och tillhandahåller sätt att påverka kompileringskodens genereringspolicy. För de senare kan olika optimeringskvaliteter ges värden mellan 0 (inte viktigt) och 3 (viktigast): hastighet , utrymme , säkerhet , felsökning och kompilationshastighet .
Det finns också en funktion för att utvärdera Lisp-kod: eval
. eval
tar kod som föranalyserade s-uttryck och inte, som på vissa andra språk, som textsträngar. På så sätt kan koden konstrueras med de vanliga Lisp -funktionerna för att konstruera listor och symboler och sedan kan denna kod utvärderas med funktionen eval
. Flera vanliga Lisp -implementeringar (som Clozure CL och SBCL) implementerar med eval
hjälp av deras kompilator. På så sätt sammanställs koden, även om den utvärderas med hjälp av funktionen eval
.
Filkompilatorn anropas med funktionen compile-file . Den genererade filen med kompilerad kod kallas en fasl -fil (från snabb laddning ). Dessa FasL filer och även källkodsfiler kan laddas med funktionen last i en löpande Common Lisp-system. Beroende på implementering genererar filkompilatorn byte-kod (till exempel för Java Virtual Machine ), C- språkkod (som sedan sammanställs med en C-kompilator) eller direkt native kod.
Vanliga Lisp -implementeringar kan användas interaktivt, även om koden blir helt kompilerad. Idén om ett tolkat språk gäller alltså inte för interaktiva Common Lisp.
Språket gör skillnad mellan lästid, kompileringstid, laddningstid och körtid, och tillåter användarkod att också göra denna åtskillnad för att utföra den önskade typen av behandling vid det önskade steget.
Vissa specialoperatörer tillhandahålls för att passa särskilt interaktiv utveckling; Till exempel defvar
kommer bara att tilldela ett värde till den angivna variabeln om den inte redan var bunden, medan den defparameter
alltid kommer att utföra tilldelningen. Denna skillnad är användbar när man interaktivt utvärderar, kompilerar och laddar kod i en levande bild.
Vissa funktioner tillhandahålls också för att skriva kompilatorer och tolkar. Symboler består av objekt på första nivån och är direkt manipulerbara med användarkod. Den progv
speciella operatören tillåter att skapa lexikaliska bindningar programmatiskt, medan paket också är manipulerbara. Lisp -kompilatorn är tillgänglig vid körning för att kompilera filer eller enskilda funktioner. Dessa gör det enkelt att använda Lisp som en mellankompilerare eller tolk för ett annat språk.
Födelsedagsparadox
Följande program beräknar det minsta antalet personer i ett rum för vilka sannolikheten för unika födelsedagar är mindre än 50% ( födelsedagsparadoxen , där sannolikheten för 1 person är uppenbarligen 100%, för 2 är det 364/365, etc. ). Svaret är 23.
Enligt konventionen omsluts konstanter i Common Lisp med + tecken.
(defconstant +year-size+ 365)
(defun birthday-paradox (probability number-of-people)
(let ((new-probability (* (/ (- +year-size+ number-of-people)
+year-size+)
probability)))
(if (< new-probability 0.5)
(1+ number-of-people)
(birthday-paradox new-probability (1+ number-of-people)))))
CL-USER > (birthday-paradox 1.0 1)
23
Sortera en lista över personobjekt
Vi definierar en klass person
och en metod för att visa namn och ålder på en person. Därefter definierar vi en grupp personer som en lista med person
objekt. Sedan går vi igenom den sorterade listan.
(defclass person ()
((name :initarg :name :accessor person-name)
(age :initarg :age :accessor person-age))
(:documentation "The class PERSON with slots NAME and AGE."))
(defmethod display ((object person) stream)
"Displaying a PERSON object to an output stream."
(with-slots (name age) object
(format stream "~a (~a)" name age)))
(defparameter *group*
(list (make-instance 'person :name "Bob" :age 33)
(make-instance 'person :name "Chris" :age 16)
(make-instance 'person :name "Ash" :age 23))
"A list of PERSON objects.")
(dolist (person (sort (copy-list *group*)
#'>
:key #'person-age))
(display person *standard-output*)
(terpri))
Den skriver ut de tre namnen med fallande ålder.
Bob (33)
Ash (23)
Chris (16)
Exponentierar genom kvadrering
Användning av LOOP -makrot visas:
(defun power (x n)
(loop with result = 1
while (plusp n)
when (oddp n) do (setf result (* result x))
do (setf x (* x x)
n (truncate n 2))
finally (return result)))
Exempel på användning:
CL-USER > (power 2 200)
1606938044258990275541962092341162602522202993782792835301376
Jämför med den inbyggda exponentieringen:
CL-USER > (= (expt 2 200) (power 2 200))
T
Hitta listan över tillgängliga skal
WITH-OPEN-FILE är ett makro som öppnar en fil och tillhandahåller en ström. När formuläret återkommer stängs filen automatiskt. FUNCALL kallar ett funktionsobjekt. LOOP samlar alla rader som matchar predikatet.
(defun list-matching-lines (file predicate)
"Returns a list of lines in file, for which the predicate applied to
the line returns T."
(with-open-file (stream file)
(loop for line = (read-line stream nil nil)
while line
when (funcall predicate line)
collect it)))
Funktionen AVAILABLE-SHELLS anropar ovanför funktionen LIST-MATCHING-LINES med ett söknamn och en anonym funktion som predikat. Predikatet returnerar sökvägsnamnet för ett skal eller NIL (om strängen inte är filnamnet på ett skal).
(defun available-shells (&optional (file #p"/etc/shells"))
(list-matching-lines
file
(lambda (line)
(and (plusp (length line))
(char= (char line 0) #\/)
(pathname
(string-right-trim '(#\space #\tab) line))))))
Exempelresultat (på Mac OS X 10.6):
CL-USER > (available-shells)
(#P"/bin/bash" #P"/bin/csh" #P"/bin/ksh" #P"/bin/sh" #P"/bin/tcsh" #P"/bin/zsh")
Vanliga Lisp jämförs oftast med och står i kontrast till Scheme - om det bara är för att de är de två mest populära Lisp -dialekterna. Scheme föregår CL och kommer inte bara från samma Lisp -tradition utan från några av samma ingenjörer - Guy L. Steele , som Gerald Jay Sussman utformade Scheme med, ledde standardkommittén för Common Lisp.
Common Lisp är ett generellt programmeringsspråk, till skillnad från Lisp-varianter som Emacs Lisp och AutoLISP som är tilläggsspråk inbäddade i vissa produkter (GNU Emacs respektive AutoCAD). Till skillnad från många tidigare Lisps, Common Lisp (som Scheme ) använder lexikala variabel omfattning som standard för både tolkas och kompilerad kod.
De flesta av Lisp -systemen vars konstruktioner bidrog till Common Lisp - som ZetaLisp och Franz Lisp - använde dynamiskt omfattande variabler i sina tolkar och lexiskt omfattande variabler i sina kompilatorer. Scheme introducerade den enda användningen av lexiskt omfattande variabler till Lisp; en inspiration från ALGOL 68 . CL stöder också dynamiskt omfattande variabler, men de måste uttryckligen deklareras som "speciella". Det finns inga skillnader i omfattningen mellan ANSI CL -tolkar och kompilatorer.
Common Lisp kallas ibland Lisp-2 och Scheme a Lisp-1 , med hänvisning till CL: s användning av separata namnområden för funktioner och variabler. (Faktum är att CL har många namnutrymmen, till exempel de för go -taggar, blocknamn och loop
sökord). Det finns en långvarig kontrovers mellan CL och Scheme-förespråkare om avvägningarna i flera namnområden. I Scheme är det (i stort) nödvändigt att undvika att ge variabler namn som krockar med funktioner; Schemafunktioner har ofta argument med namnet lis
, lst
eller lyst
för att inte komma i konflikt med systemfunktionen list
. I CL är det dock nödvändigt att uttryckligen hänvisa till funktionsnamnsutrymmet när en funktion skickas som ett argument - vilket också är en vanlig förekomst, som i sort
exemplet ovan.
CL skiljer sig också från Scheme i sin hantering av booleska värden. Scheme använder de speciella värdena #t och #f för att representera sanning och falskhet. CL följer den äldre Lisp -konventionen att använda symbolerna T och NIL, med NIL som står för den tomma listan. I CL behandlas alla icke-NIL-värden som sanna av villkor, t.ex. if
i Scheme behandlas alla icke-#f-värden som sanna. Dessa konventioner gör det möjligt för vissa operatörer på båda språken att fungera både som predikat (svara på en boolsk värderad fråga) och som att returnera ett användbart värde för ytterligare beräkning, men i Scheme värderas värdet '() som motsvarar NIL i Common Lisp till sant i ett booleskt uttryck.
Slutligen kräver Scheme-standarddokumenten optimering av tail-call , vilket CL-standarden inte gör. De flesta CL-implementeringar erbjuder optimering av tail-call, men ofta bara när programmeraren använder ett optimeringsdirektiv. Ändå gör gemensam CL kodning stil inte gynna den allestädes närvarande användningen av rekursion att Scheme stil föredrar, vad en Scheme programmerare skulle uttrycka med svans rekursion, en CL användaren skulle vanligtvis uttrycka med en iterativ uttryck i do
, dolist
, loop
eller (mer nyligen) med iterate
paket.
Se kategorin Common Lisp -implementeringar .
Common Lisp definieras av en specifikation (som Ada och C ) snarare än av en implementering (som Perl ). Det finns många implementeringar och standarddetaljerna där de giltigt kan skilja sig åt.
Dessutom tenderar implementationer att komma med tillägg, som ger funktionalitet som inte omfattas av standarden:
- Interaktiv toppnivå (REPL)
- Skräp samling
- Debugger, Stepper och Inspector
- Svaga datastrukturer (hashtabeller)
- Förlängningsbara sekvenser
- Förlängningsbar LOOP
- Tillgång till miljö
- CLOS Meta-object Protocol
- CLOS -baserade utökningsbara strömmar
- CLOS -baserat skicksystem
- Nätverksströmmar
- Ihållande STÄNG
- Unicode -stöd
- Utländskt språkgränssnitt (ofta till C)
- Operativsystemgränssnitt
- Java -gränssnitt
- Trådar och multiprocessing
- Applikationsleverans (applikationer, dynamiska bibliotek)
- Spara bilder
Gratis och öppen källkodsprogram har skapats för att stödja tillägg till Common Lisp på ett portabelt sätt och finns framför allt i databaserna för projekten Common-Lisp.net och CLOCC (Common Lisp Open Code Collection).
Vanliga Lisp -implementeringar kan använda valfri blandning av inbyggd kodsamling, byte -kodsamling eller tolkning. Common Lisp har utformats för att stödja inkrementella kompilatorer , filkompilatorer och blockkompilatorer. Standarddeklarationer för att optimera sammanställningen (t.ex. funktionsinlining eller typspecialisering) föreslås i språkspecifikationen. De flesta vanliga Lisp -implementeringar sammanställer källkod till inbyggd maskinkod . Vissa implementeringar kan skapa (optimerade) fristående applikationer. Andra kompilerar till tolkad bytecode , vilket är mindre effektivt än inbyggd kod, men underlättar binär kodportabilitet. Vissa kompilatorer kompilerar Common Lisp -kod till C -kod. Missuppfattningen att Lisp är ett rent tolkat språk beror troligen på att Lisp-miljöer tillhandahåller en interaktiv prompt och att koden sammanställs en efter en, stegvis. Med Common Lisp används inkrementell sammanställning i stor utsträckning.
Vissa Unix -baserade implementeringar ( CLISP , SBCL ) kan användas som skriptspråk ; det vill säga åberopas av systemet transparent på det sätt som en Perl- eller Unix -skaltolkare är.
Lista över implementeringar
Kommersiella implementeringar
- Allegro Common Lisp
- för Microsoft Windows, FreeBSD, Linux, Apple macOS och olika UNIX -varianter. Allegro CL tillhandahåller en integrerad utvecklingsmiljö (IDE) (för Windows och Linux) och omfattande funktioner för applikationsleverans.
- Liquid Common Lisp
- hette tidigare Lucid Common Lisp . Endast underhåll, inga nya utgåvor.
- LispWorks
- för Microsoft Windows, FreeBSD, Linux, Apple macOS, iOS, Android och olika UNIX -varianter. LispWorks tillhandahåller en integrerad utvecklingsmiljö (IDE) (tillgänglig för de flesta plattformar, men inte för iOS och Android) och omfattande funktioner för applikationsleverans.
- mocl
- för iOS, Android och macOS.
- Öppna släkten
- för DEC Alpha.
- Scieneer Common Lisp
- som är utformad för högpresterande vetenskaplig datorer.
Fritt distribuerbara implementeringar
- Armed Bear Common Lisp (ABCL)
- En CL -implementering som körs på Java Virtual Machine . Den innehåller en kompilator till Java -bytekod och ger åtkomst till Java -bibliotek från CL. Det var tidigare bara en del av Armed Bear J Editor .
- CLISP
- En byte-kodkompilerande implementering, bärbar och körs på flera Unix- och Unix-liknande system (inklusive macOS ), samt Microsoft Windows och flera andra system.
- Clozure CL (CCL)
- Ursprungligen en gratis och öppen källkorgsgaffel av Macintosh Common Lisp. Som historien antyder skrevs CCL för Macintosh, men Clozure CL körs nu på macOS , FreeBSD , Linux , Solaris och Windows . 32 och 64 bitars x86 -portar stöds på varje plattform. Dessutom finns Power PC -portar för Mac OS och Linux. CCL var tidigare känt som OpenMCL, men det namnet används inte längre för att undvika förvirring med open source -versionen av Macintosh Common Lisp.
- CMUCL
- Corman Common Lisp
- för Microsoft Windows. I januari 2015 har Corman Lisp publicerats under MIT -licens.
- Inbyggd gemensam lisp (ECL)
- ECL innehåller en byte -tolk och kompilator. Det kan också kompilera Lisp -kod till maskinkod via en C -kompilator. ECL sammanställer sedan Lisp -kod till C, kompilerar C -koden med en C -kompilator och kan sedan ladda den resulterande maskinkoden. Det är också möjligt att bädda in ECL i C -program och C -kod i Common Lisp -program.
- GNU Common Lisp (GCL)
- Den GNU projektets Lisp-kompilator. GCL är ännu inte helt ANSI-kompatibelt, men implementerar det valda för flera stora projekt, inklusive de matematiska verktygen Maxima , AXIOM och (historiskt) ACL2 . GCL körs på Linux under elva olika arkitekturer, och även under Windows, Solaris och FreeBSD .
- Macintosh Common Lisp (MCL)
- Version 5.2 för Apple Macintosh -datorer med en PowerPC -processor med Mac OS X är öppen källkod. RMCL (baserat på MCL 5.2) körs på Intel-baserade Apple Macintosh-datorer med Rosetta binära översättare från Apple.
- ManKai Common Lisp (MKCL)
- En gren av ECL . MKCL betonar tillförlitlighet, stabilitet och övergripande kodkvalitet genom ett kraftigt omarbetat, inbyggt multi-threaded, runtime-system. På Linux har MKCL ett fullt POSIX -kompatibelt körningssystem.
- Movitz
- Implementerar en Lisp -miljö för x86 -datorer utan att förlita sig på något underliggande operativsystem.
- Poplog
- Poplog implementerar en version av CL, med POP-11 , och eventuellt Prolog , och Standard ML (SML), vilket möjliggör blandad programmering. För alla är implementeringsspråket POP-11, som sammanställs stegvis. Den har också en integrerad Emacs -liknande editor som kommunicerar med kompilatorn.
- Steel Bank Common Lisp (SBCL)
- En gren från CMUCL . "I stort sett skiljer sig SBCL från CMU CL genom en större betoning på underhållbarhet." SBCL körs på plattformarna CMUCL gör, förutom HP/UX; Dessutom körs det på Linux för AMD64, PowerPC, SPARC, MIPS, Windows x86 och har experimentellt stöd för körning på Windows AMD64. SBCL använder inte en tolk som standard; alla uttryck sammanställs till inbyggd kod om inte användaren slår på tolk. SBCL -kompilatorn genererar snabb inbyggd kod enligt en tidigare version av The Computer Language Benchmarks Game .
- Ufasoft Common Lisp
- CLISP -port för Windows -plattform med kärna skriven i C ++.
Andra implementeringar
- Austin Kyoto Common Lisp
- en utveckling av Kyoto Common Lisp av Bill Schelter
- Butterfly Common Lisp
- en implementering skriven i Scheme för BBN Butterfly multi-processor dator
- KLICKA
- en gemensam Lisp till C -kompilator
- CLOE
- Vanlig Lisp för datorer av Symbolics
- Codemist Common Lisp
- används för den kommersiella versionen av datoralgebrasystemet Axiom
- Experiment Vanlig Lisp
- en tidig implementering för Apple Macintosh av ExperTelligence
- Golden Common Lisp
- en implementering för datorn av GoldHill Inc.
- Ibuki Common Lisp
- en kommersialiserad version av Kyoto Common Lisp
- Kyoto Common Lisp
- den första Common Lisp -kompilatorn som använde C som målspråk. GCL, ECL och MKCL kommer från denna gemensamma Lisp -implementering.
- L
- en liten version av Common Lisp för inbäddade system som utvecklats av IS Robotics, nu iRobot
- Lisp Machines (från Symbolics , TI och Xerox)
- tillhandahållit implementeringar av Common Lisp förutom deras ursprungliga Lisp -dialekt (Lisp Machine Lisp eller Interlisp). CLOS var också tillgängligt. Symbolics ger en förbättrad version Common Lisp.
- Procyon Common Lisp
- en implementering för Windows och Mac OS, som används av Franz för deras Windows -port i Allegro CL
- Star Sapphire Common LISP
- en implementering för datorn
- SubL
- en variant av Common Lisp som används för implementering av det kunskapsbaserade Cyc -systemet
- Top Level Common Lisp
- en tidig implementering för samtidig körning
- WCL
- en implementering av delat bibliotek
- VAX Common Lisp
- Digital Equipment Corporation implementering som kördes på VAX -system som kör VMS eller ULTRIX
- XLISP
- en implementering skriven av David Betz
Common Lisp används för att utveckla forskningsapplikationer (ofta inom artificiell intelligens ), för snabb utveckling av prototyper eller för distribuerade applikationer.
Common Lisp används i många kommersiella applikationer, inklusive Yahoo! Store webb-handelsplats, som ursprungligen involverade Paul Graham och senare skrevs om i C ++ och Perl . Andra anmärkningsvärda exempel inkluderar:
- ACT-R , en kognitiv arkitektur som används i ett stort antal forskningsprojekt.
- Authorizer's Assistant, ett stort regelbaserat system som används av American Express, som analyserar kreditförfrågningar.
- Cyc , ett långsiktigt projekt för att skapa ett kunskapsbaserat system som ger en enorm mängd sunt förnuft.
- Gensym G2 , ett expertsystem i realtid och affärsregler
- Genworks GDL, baserat på Gendl-kärnan med öppen källkod.
- Utvecklingsmiljön för Jak och Daxter videospel -serien, utvecklad av Naughty Dog .
- ITA Softwares lågpris -sökmotor, som används av resehemsidor som Orbitz och Kayak.com och flygbolag som American Airlines , Continental Airlines och US Airways .
- Mirai , en 3D -grafiksvit. Den användes för att animera ansiktet på Gollum i filmen Sagan om ringen: De två tornen .
- Opusmodus är ett musikkompositionssystem baserat på Common Lisp, som används i datorassisterad komposition .
- Prototype Verification System (PVS), en mekaniserad miljö för formell specifikation och verifiering.
- PWGL är en sofistikerad visuell programmeringsmiljö baserad på Common Lisp, som används i datorassisterad komposition och ljudsyntes.
- Piano, en komplett flygplananalyssvit, skriven i Common Lisp, som används av företag som Boeing , Airbus och Northrop Grumman .
- Grammarly , en engelskspråkig skrivförbättringsplattform, har sin grundläggande grammatikmotor skriven i Common Lisp.
- Den dynamiska analysen och omplanering Tool (DART), som sägs ensam har betalat tillbaka under åren 1991-1995 för alla trettio år av DARPA investeringar i AI forskning.
- NASA : s Jet Propulsion Lab 's " Deep Space 1 ", en prisbelönt Common Lisp program för autopiloting av Deep Space One rymdskepp.
- SigLab, en gemensam Lisp -plattform för signalbehandling som används vid missilförsvar, byggd av Raytheon .
- NASA: s Mars Pathfinder Mission Planning System.
- SPIKE, ett schemaläggningssystem för jord- eller rymdbaserade observatorier och satelliter, särskilt Hubble -rymdteleskopet, skrivet i Common Lisp.
- Common Lisp har använts för att prototypera sophämtaren för Microsofts .NET Common Language Runtime .
- Den ursprungliga versionen av Reddit , även om utvecklarna senare bytte till Python på grund av bristen på bibliotek för Common Lisp, enligt ett officiellt blogginlägg av Reddit-grundare Steve Huffman .
Det finns också program med öppen källkod skriven i Common Lisp, till exempel:
- ACL2 , ett fullfjädrat automatiserat teoremprover för en applikativ variant av Common Lisp.
- Axiom , ett sofistikerat datoralgebrasystem .
- Maxima , ett sofistikerat datoralgebrasystem , baserat på Macsyma.
- OpenMusic , en objektorienterad visuell programmeringsmiljö baserad på Common Lisp, som används i datorassisterad komposition .
- Pgloader, en datalastare för PostgreSQL , som skrevs om från Python till Common Lisp.
- Stumpwm , en plattor, tangentborddriven X11 Window Manager skriven helt i Common Lisp.
En kronologisk lista över böcker som publiceras (eller håller på att publiceras) om Common Lisp (språket) eller om programmering med Common Lisp (särskilt AI -programmering).
- Guy L. Steele : Common Lisp the Language, 1st Edition , Digital Press, 1984, ISBN 0-932376-41-X
- Rodney Allen Brooks : Programming in Common Lisp , John Wiley and Sons Inc, 1985, ISBN 0-471-81888-7
- Richard P. Gabriel : Prestanda och utvärdering av Lisp-system , The MIT Press, 1985, ISBN 0-262-57193-5 , PDF
- Robert Wilensky : Common LISPcraft , WW Norton & Co., 1986, ISBN 0-393-95544-3
- Eugene Charniak , Christopher K. Riesbeck , Drew V. McDermott , James R. Meehan : Artificial Intelligence Programming, 2nd Edition , Lawrence Erlbaum, 1987, ISBN 0-89859-609-2
- Wendy L. Milner : Common Lisp: A Tutorial , Prentice Hall, 1987, ISBN 0-13-152844-0
- Deborah G. Tatar : A Programmer's Guide to Common Lisp , Longman Higher Education, 1987, ISBN 0-13-728940-5
- Taiichi Yuasa , Masami Hagiya : Introduction to Common Lisp , Elsevier Ltd, 1987, ISBN 0-12-774860-1
- Christian Queinnec , Jerome Chailloux : Lisp Evolution and Standardization , Ios Pr Inc., 1988, ISBN 90-5199-008-1
- Taiichi Yuasa , Richard Weyhrauch , Yasuko Kitajima : Common Lisp Drill , Academic Press Inc, 1988, ISBN 0-12-774861-X
- Wade L. Hennessey : Common Lisp , McGraw-Hill Inc., 1989, ISBN 0-07-028177-7
- Tony Hasemer , John Dominque : Common Lisp Programming for Artificial Intelligence , Addison-Wesley Educational Publishers Inc, 1989, ISBN 0-201-17579-7
- Sonya E. Keene : Object-Oriented Programming in Common Lisp: A Programmer's Guide to CLOS , Addison-Wesley, 1989, ISBN 0-201-17589-4
- David Jay Steele : Golden Common Lisp: A Hands-On Approach , Addison Wesley, 1989, ISBN 0-201-41653-0
- David S. Touretzky : Common Lisp: A Gentle Introduction to Symbolic Computation , Benjamin-Cummings, 1989, ISBN 0-8053-0492-4 . Web/PDF Dover-tryckning (2013) ISBN 978-0486498201
- Christopher K. Riesbeck , Roger C. Schank : Inside Case-Based Reasoning , Lawrence Erlbaum, 1989, ISBN 0-89859-767-6
- Patrick Winston , Berthold Horn : Lisp, 3: e upplagan , Addison-Wesley, 1989, ISBN 0-201-08319-1 , Web
- Gerard Gazdar , Chris Mellish : Natural Language Processing in LISP: An Introduction to Computational Linguistics , Addison-Wesley Longman Publishing Co., 1990, ISBN 0-201-17825-7
- Patrick R. Harrison : Common Lisp and Artificial Intelligence , Prentice Hall PTR, 1990, ISBN 0-13-155243-0
- Timothy Koschmann : The Common Lisp Companion , John Wiley & Sons, 1990, ISBN 0-471-50308-8
- W. Richard Stark : LISP, Lore och Logic , Springer Verlag New York Inc., 1990, ISBN 978-0-387-97072-1 , PDF
- Molly M. Miller , Eric Benson : Lisp Style & Design , Digital Press, 1990, ISBN 1-55558-044-0
- Guy L. Steele : Common Lisp the Language , andra upplagan , Digital Press, 1990, ISBN 1-55558-041-6 , Web
- Robin Jones, Clive Maynard , Ian Stewart: The Art of Lisp Programming , Springer Verlag New York Inc., 1990, ISBN 978-3-540-19568-9 , PDF
- Steven L. Tanimoto : Elements of Artificial Intelligence Using Common Lisp , Computer Science Press, 1990, ISBN 0-7167-8230-8
- Peter Lee : Ämnen i avancerad språkimplementering , The MIT Press, 1991, ISBN 0-262-12151-4
- John H. Riley : A Common Lisp Workbook , Prentice Hall, 1991, ISBN 0-13-155797-1
- Peter Norvig : Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp , Morgan Kaufmann, 1991, ISBN 1-55860-191-0 , Web
- Gregor Kiczales , Jim des Rivieres , Daniel G. Bobrow : The Art of the Metaobject Protocol , The MIT Press, 1991, ISBN 0-262-61074-4
- Jo A. Lawless , Molly M. Miller : Understanding CLOS: The Common Lisp Object System , Digital Press, 1991, ISBN 0-13-717232-X
- Mark Watson: Common Lisp Modules: Artificial Intelligence in the Era of Neural Networks and Chaos Theory , Springer Verlag New York Inc., 1991, ISBN 0-387-97614-0 , PDF
- James L. Noyes : Artificiell intelligens med gemensam lisp: Fundamentals of Symbolic and Numeric Processing , Jones & Bartlett Pub, 1992, ISBN 0-669-19473-5
- Stuart C. Shapiro : COMMON LISP: An Interactive Approach , Computer Science Press, 1992, ISBN 0-7167-8218-9 , Web/PDF
- Kenneth D. Forbus , Johan de Kleer : Building Problem Solvers , The MIT Press, 1993, ISBN 0-262-06157-0
- Andreas Paepcke : Objektorienterad programmering: CLOS-perspektivet , The MIT Press, 1993, ISBN 0-262-16136-2
- Paul Graham : On Lisp , Prentice Hall, 1993, ISBN 0-13-030552-9 , Webb/PDF
- Paul Graham : ANSI Common Lisp , Prentice Hall, 1995, ISBN 0-13-370875-6
- Otto Mayer : Programmieren in Common Lisp , German, Spektrum Akademischer Verlag, 1995, ISBN 3-86025-710-2
- Stephen Slade : Object-Oriented Common Lisp , Prentice Hall, 1997, ISBN 0-13-605940-6
- Richard P. Gabriel : Patterns of Software: Tales from the Software Community , Oxford University Press, 1998, ISBN 0-19-512123-6 , PDF
- Taiichi Yuasa , Hiroshi G. Okuno : Advanced Lisp Technology , CRC, 2002, ISBN 0-415-29819-9
- David B. Lamkins : Successful Lisp: How to Understand and Use Common Lisp , bookfix.com, 2004. ISBN 3-937526-00-5 , Web
- Peter Seibel : Practical Common Lisp , Apress, 2005. ISBN 1-59059-239-5 , Web
- Doug Hoyte : Let Over Lambda , Lulu.com, 2008, ISBN 1-4357-1275-7 , Web
- Conrad Barski : Land of Lisp: Lär dig att programmera i Lisp, ett spel i taget! , No Starch Press, 2010, ISBN 1-59327-200-6 , Web
- Pavel Penev : Lisp Web Tales , Leanpub, 2013, webb
- Edmund Weitz : Common Lisp Recipes , Apress, 2015, ISBN 978-1-484211-77-9 , Web
- Patrick M. Krusenotto : Funktionale Programmierung und Metaprogrammierung, Interaktiv in Common Lisp , Springer Fachmedien Wiesbaden 2016, ISBN 978-3-658-13743-4 , Web
- Quicklisp - En mycket populär och högkvalitativ bibliotekschef för Common Lisp
- Den enorma CL listan, en kurator lista över Common Lisp ramar och bibliotek.
- The Common Lisp Cookbook , ett samarbetsprojekt.
- Den CLiki en Wiki för fri och öppen källkod Common Lisp-system som körs på Unix-liknande system.
- En av de viktigaste lagren för gratis Common Lisp för programvara är Common-Lisp.net .
- lisp-lang.org har dokumentation och en uppvisning av framgångshistorier.
- En översikt över Common Lisp: "History" . Vanlig Lisp HyperSpec .
- Common Lisp Quick Reference - en kompakt översikt över Common Lisp -standardspråket.
- Planet Lisp Artiklar om Common Lisp.
- Quickdocs sammanfattar dokumentation och beroendeinformation för många Quicklisp -projekt.