Vanlig Lisp
Paradigm | Multiparadigm : procedurmässigt , 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én |
Dök först upp | 1984 | , 1994 för ANSI Common Lisp
Maskinskrivningsdisciplin | Dynamisk , stark |
Omfattning | Lexikal, valfritt dynamisk |
OS | Cross-plattform |
Filnamnstillägg | .lisp, .lsp, .l, .cl, .fasl |
Hemsida | |
Stora implementeringar | |
Allegro CL , ABCL , Clasp, , Clozure CL , CMUCL , ECL , GCL , LispWorks , Scieneer CL, SBCL , Symbolics Common Lisp | |
Influenced CLISP Lisp , Lisp Machine Schema , Lisp Machine Schema Interlisp | |
Dialects | |
CLtL1, CLtL2, ANSI Common Lisp | |
by | |
Influenced | |
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 standarddokument ANSI INCITS 226-1994 (S20018) (tidigare X3.226-1994 (R1999) ) . Common Lisp HyperSpec , en hyperlänkad HTML- version, har härletts från ANSI Common Lisp-standarden.
Common Lisp-språket utvecklades som en standardiserad och förbättrad efterföljare till Maclisp . I början av 1980-talet var flera grupper redan igång med olika efterföljare 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 en implementering, utan snarare en språkspecifikation . Flera implementeringar av Common Lisp-standarden är tillgängliga, inklusive gratis och öppen källkod och proprietära produkter. Common Lisp är ett multiparadigm programmeringsspråk för allmänna ändamål . Den stöder en kombination av procedurmässiga , funktionella och objektorienterade programmeringsparadigm . Som ett dynamiskt programmeringsspråk underlättar det evolutionär och inkrementell mjukvaruutveckling , med iterativ kompilering till effektiva körtidsprogram. Denna inkrementella utveckling görs ofta interaktivt utan att avbryta den pågående applikationen.
Den stöder också valfri typkommentar och casting, som kan läggas till vid behov vid senare profilerings- och optimeringsstadier, för att tillåta kompilatorn att generera mer effektiv kod. Till exempel fixnum
innehålla ett heltal utan förpackning 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 få besked per modul eller per funktion vilken typ av säkerhetsnivå som önskas, med hjälp av optimeringsdeklarationer .
Common Lisp inkluderar CLOS , ett objektsystem som stöder multimetoder och metodkombinationer. Det implementeras ofta med ett Metaobject Protocol.
Common Lisp kan utökas med standardfunktioner som Lisp- makron (kodtransformationer) och läsarmakron (indataparsers för tecken).
Common Lisp ger delvis bakåtkompatibilitet med Maclisp och John McCarthys original Lisp . Detta gör att äldre Lisp-programvara kan portas till Common Lisp.
Historia
Arbetet med Common Lisp startade 1981 efter ett initiativ av ARPA-chefen Bob Engelmore för att utveckla en enda gemenskapsstandard Lisp-dialekt. Mycket av den ursprungliga språkdesignen gjordes via e-post. 1982 Guy L. Steele Jr. den första översikten av Common Lisp vid 1982 ACM Symposium 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 utgåva (känd som CLtL2), publicerad 1990, innehöll 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 ANSI Common Lisp-standarden och är därför inte en 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-baserad IO) har tillhandahållits av implementeringar och bibliotek.
Syntax
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 namnet på operatören först, som i dessa exempel:
( +22 ) ; _ _ lägger till 2 och 2, vilket ger 4. Funktionens namn är '+'. Lisp har inga operatörer som sådana.
( defvar *x* ) ; Säkerställer att en variabel *x* finns, ; utan att ge det ett värde. Asteriskerna är en del av ; namnet, enligt konvention som betecknar en speciell (global) variabel. ; Symbolen *x* förses också härmed med egenskapen att ; efterföljande bindningar av det är dynamiska, snarare än lexikaliska. ( setf *x* 42.1 ) ; Ställer in variabeln *x* till flyttalsvärdet 42,1
;; Definiera en funktion som kvadrerar ett tal: ( defun square ( x ) ( * x x ))
;; Utför funktionen: ( ruta 3 ) ; Returnerar 9
;; "Låt"-konstruktionen skapar ett utrymme för lokala variabler. Här ;; variabeln 'a' är bunden till 6 och variabeln 'b' är bunden ;; till 4. Inuti 'let' finns en 'body', där det senast beräknade värdet returneras. ;; Här returneras resultatet av att lägga till a och b från uttrycket 'låt'. ;; Variablerna a och b har lexikalisk omfattning, såvida inte symbolerna har varit ;; markerade som speciella variabler (till exempel av en tidigare DEFVAR). ( låt (( a 6 ) ( b 4 )) ( + a b )) ; returnerar 10
Datatyper
Common Lisp har många datatyper .
Skalära typer
Taltyper inkluderar heltal , kvoter , 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 bråkdelar exakt, en funktion som inte är tillgänglig på många språk. Common Lisp tvingar automatiskt numeriska värden bland dessa typer efter behov.
Teckentypen Common Lisp är inte begränsad till ASCII- tecken. De flesta moderna implementeringar tillåter Unicode- tecken.
Symboltypen är gemensam för Lisp-språk, men i stort sett okänd utanför dem . En symbol är ett unikt namngivet dataobjekt med flera delar: namn, värde, funktion, egenskapslista och paket. Av dessa värdecell och funktionscell 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 sig själva, till exempel är alla symboler i nyckelordspaketet självutvärderande. Booleska 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 finns tillgängliga för att avrunda skalära numeriska värden på olika sätt. Funktionen rundar
av argumentet till närmaste heltal, med halvvägs fall avrundade till det jämna heltal. Funktionerna trunkera
, golv
och tak
avrunda mot noll, ner respektive uppåt. Alla dessa funktioner returnerar den kasserade bråkdelen som ett sekundärt värde. Till exempel, (golv -2,5)
ger −3, 0,5; (tak -2,5)
ger −2, −0,5; (omgång 2,5)
ger 2, 0,5; och (omgång 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 sekvenstyp som helst.
Som i nästan alla andra Lisp-dialekter är listor i Common Lisp sammansatta av conses , ibland kallade cons-celler eller par . En nackdel är en datastruktur med två platser, som kallas dess bil och cdr . En lista är en länkad kedja av fördelar eller den tomma listan. Varje nackdelars bil hänvisar till en medlem i listan (eventuellt en annan lista). Varje nackdelars cdr hänvisar till nästa nackdelar – förutom de sista nackdelarna i en lista, vars cdr refererar till nollvärdet
. Conses 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 conses.
Common Lisp stöder flerdimensionella arrayer och kan dynamiskt ändra storlek på justerbara arrayer om det behövs. Flerdimensionella arrayer kan användas för matrismatematik. En vektor är en endimensionell array. Arrayer kan bära vilken typ som helst som medlemmar (även blandade typer i samma array) eller kan vara specialiserade för att innehålla en specifik typ av medlemmar, som i en vektor av bitar. Vanligtvis stöds bara ett fåtal typer. Många implementeringar kan optimera arrayfunktioner när arrayen som används är typspecialiserad. Två typspecialiserade arraytyper är standard: en sträng är en vektor av tecken, medan en bitvektor är en vektor av bitar .
Hash-tabeller lagrar associationer mellan dataobjekt. Vilket objekt som helst kan användas som nyckel eller värde. Hash-tabeller ändras automatiskt efter behov.
Paket är samlingar av symboler, som främst används för att separera delarna av ett program i namnutrymmen . 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 enkelarv.
Klasser liknar strukturer, men erbjuder mer dynamiska funktioner och multipelt arv. (Se STÄNG ). Klasser har lagts till sent i Common Lisp och det finns en viss begreppsmässig överlappning med strukturer. Objekt skapade 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 också returnera funktioner. Detta gör det möjligt att beskriva mycket generella operationer.
Common Lisp-biblioteket är starkt beroende av sådana funktioner av högre ordning. Till exempel tar sorteringsfunktionen en
relationsoperator som ett argument och nyckelfunktionen som ett valfritt nyckelordsargument. 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.
;; Sorterar listan med funktionen > och < som relationsoperator. ( sortera ( lista 5 2 6 3 1 4 ) #' > ) ; Returnerar (6 5 4 3 2 1) ( sortera ( lista 5 2 6 3 1 4 ) #' < ) ; Returer (1 2 3 4 5 6)
;; Sorterar listan enligt det första elementet i varje underlista. ( sortera ( lista ' ( 9 A ) ' ( 3 B ) ' ( 4 C ) ) # ' < : nyckel # ' först ) ; Returnerar ((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...)
då förutsätter den att symbolen med namnet f är en av följande:
- En speciell operatör (enkelt kontrolleras mot en fast lista)
- En makrooperator (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, så utvärderas argumenten a1, a2, ..., an i ordning från vänster till höger, och funktionen hittas och anropas med de värden som anges som parametrar.
Definiera funktioner
Makro defun definierar funktioner där en funktionsdefinition ger namnet
på funktionen, namnen på eventuella argument och en funktionskropp:
( defun square ( x ) ( * x x ))
Funktionsdefinitioner kan inkludera kompilatordirektiv , kända som deklarationer , som ger kompilatorn tips om optimeringsinställningar eller datatyper av argument. De kan också inkludera dokumentationssträngar (docstrings), som Lisp-systemet kan använda för att tillhandahålla interaktiv dokumentation:
0
( defun square ( x ) "Beräknar kvadraten av single-float x." ( declare ( single-float x ) ( optimize ( speed 3 ) ( debug ) ( safety 1 ))) ( single -float ( * x x ) )))
Anonyma funktioner ( funktionsliterals ) definieras med lambda-
uttryck, t.ex. (lambda (x) (* x x))
för en funktion som kvadrerar sitt 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 etiketter
.
( flet (( square ( x ) ( * x x ))) ( ruta 3 ))
Det finns flera andra operatörer relaterade till definition och manipulering av funktioner. Till exempel kan en funktion kompileras med kompileringsoperatorn
. (Vissa Lisp-system kör funktioner med hjälp av en tolk som standard om de inte uppmanas att kompilera; andra kompilerar varje funktion).
Definiera generiska funktioner och metoder
Makro defgeneric
definierar generiska funktioner . Generiska funktioner är en samling metoder . Makrodefmetoden definierar metoder .
Metoder kan specialisera sina parametrar över CLOS standardklasser , systemklasser , strukturklasser eller enskilda objekt. För många typer finns det motsvarande systemklasser .
När en generisk funktion anropas kommer multipelutskick att avgöra vilken effektiv metod som ska användas.
( defgeneric add ( a b ))
( defmethod add (( ett nummer ) ( b nummer )) ( + a b ))
( defmethod add (( a vektor ) ( b nummer )) ( map 'vector ( lambda ( n ) ( + n b )) a ))
( defmethod add (( a vektor ) ( b vektor )) ( map 'vector #' + a b ))
( defmethod add (( en sträng ) ( b sträng )) ( sammanfoga 'sträng a b ))
( lägg till 2 3 ) ; returnerar 5 ( lägg till #( 1 2 3 4 ) 7 ) ; returnerar #(8 9 10 11) ( lägg till #( 1 2 3 4 ) #( 4 3 2 1 )) ; returnerar #(5 5 5 5) ( lägg till "COMMON " "LISP" ) ; returnerar "COMMON LISP"
Generiska funktioner är också en förstklassig datatyp . Det finns många fler funktioner för allmänna funktioner och metoder än vad som beskrivs ovan.
Funktionens namnutrymme
Namnutrymmet för funktionsnamn är skilt från namnområdet för datavariabler. Detta är en nyckelskillnad mellan Common Lisp och Scheme . För Common Lisp inkluderar operatorer som definierar namn i funktionsnamnutrymmet defun
, flet
, labels
, defmethod
och defgeneric
.
För att skicka en funktion med namn som ett argument till en annan funktion måste man använda funktionen specialoperator
, vanligen förkortad som #'
. Det första sorteringsexemplet
ovan hänvisar till funktionen som namnges av symbolen >
i funktionsnamnrymden, med koden #'>
. Omvänt, för att anropa en funktion som skickats på ett sådant sätt, skulle man använda funcall-
operatorn på argumentet.
Schemes utvärderingsmodell är enklare: det finns bara ett namnområde, 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 i den andra. Till exempel gillar många Common Lisp-programmerare att använda beskrivande variabelnamn som listor eller strängar som kan orsaka problem i Scheme, eftersom de lokalt skulle skugga funktionsnamn.
Huruvida ett separat namnutrymme för funktioner är en fördel är en källa till diskussion 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 en artikel 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 förbli helt omedvetna om de sekundära värdena som finns där om de inte har något behov av 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,
- Funktionen
TRUNCATE
avrundar det givna talet till ett heltal mot noll. Men det returnerar också en rest som ett sekundärt värde, vilket gör det mycket enkelt att avgöra vilket värde som trunkerades. Den stöder också en valfri divisorparameter, som kan användas för att utföra euklidisk division trivialt:
( let (( x 1266778 ) ( y 458 )) ( multiple-value-bind ( quotient rest ) ( trunkate x y ) ( format noll "~A dividerat med ~A är ~A rest ~A" x y quotient rest )) ) ;;;; => "1266778 dividerat med 458 är 2765 resten 408"
-
GETHASH
returnerar värdet av en nyckel i en associativ karta , eller standardvärdet annars, och en sekundär boolean som indikerar om värdet hittades. Således kan kod som inte bryr sig om huruvida värdet hittades eller tillhandahålls som standard helt enkelt använda det som det är, men när en sådan distinktion ä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 denna funktion på språknivå tar bort behovet av att kontrollera existensen av nyckeln 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 noll "Svaret är ~A" ( get-answer library ))) ;;;; Returnerar "Svaret är 42" om SVAR inte finns i LIBRARY ( defun the-answer-2 ( library ) ( multiple-value-bind ( svara säker-p ) ( få-svar- bibliotek ) ( om ( inte säker-p ) " Jag vet inte" ( format noll "Svaret är ~A" svar )))) ;;;; Returnerar "Jag vet inte" om SVAR inte finns i LIBRARY
Flera värden stöds av en handfull standardformulär, varav de vanligaste är specialformen MULTIPLE-VALUE-BIND för att komma åt sekundära värden och
VALUES
för att returnera flera värden:
( defun magic-eight-ball () "Returnera en utsiktsförutsägelse, med sannolikheten som ett sekundärt värde" ( värden "Outlook good" ( slumpmässigt 1,0 ))) ;;;; => "Utsikterna är bra" ;;;; => 0,3187
Andra typer
Andra datatyper i Common Lisp inkluderar:
- Sökvägar representerar filer och kataloger i filsystemet . Funktionen Common Lisp-sökvägsnamn är mer allmän än de flesta operativsystems filnamnkonventioner, vilket gör Lisp-programs åtkomst till filer brett portabel över olika system.
- In- och utströmmar representerar källor och sänkor för binära eller textdata, såsom terminalen eller öppna filer.
- Common Lisp har en inbyggd pseudo-slumptalsgenerator (PRNG). Slumpmässiga tillståndsobjekt representerar återanvändbara källor för pseudoslumptal, vilket gör att användaren kan seed PRNG eller få den att spela upp 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 metaobjektklasser ( kortas metaklasser ).
- Lästabeller är en typ av objekt som styr hur Common Lisps 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.
Omfattning
Liksom program i 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 är föremål för omfattning.
Sambandet mellan ett namn och den enhet som namnet hänvisar till kallas en bindning.
Omfattning hänvisar till den uppsättning omständigheter under vilka ett namn fastställs ha en viss bindning.
Bestämmare av omfattning
De omständigheter som avgör omfattningen i Common Lisp inkluderar:
- platsen för en referens i ett uttryck. Om det är positionen längst till vänster i en förening hänvisar det till en speciell operator eller en makro- eller funktionsbindning, annars till en variabelbindning eller något annat.
- vilken typ av uttryck som referensen sker i. Till exempel
(gå x)
överföra kontroll till etikettenx
, medan(skriv ut x)
hänvisar till variabelnx
. Båda omfång avx
kan vara aktiva i samma region av programtext, eftersom tagbody-etiketter finns i ett separat namnområde från variabelnamn. En speciell form eller makroform har fullständig kontroll över betydelsen av alla symboler i sin syntax. Till exempel, i(defclass x (ab) ())
, en klassdefinition, är(ab)
en lista över basklasser, så dessa namn slås upp i utrymmet för klassnamn, ochx
är inte en referens till en befintlig bindning, men namnet på en ny klass kommer fråna
ochb
. Dessa fakta kommer enbart från semantiken idefclass
. Det enda generiska faktumet om detta uttryck är attdefclass
refererar 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 konstruktion, såsom enlet
som definierar en bindning förx
, är referensen inom det omfång som skapas av den bindningen. - för en variabelreferens, oavsett om en variabelsymbol, lokalt eller globalt, har förklarats speciell eller inte. Detta avgör om referensen löses inom en lexikal miljö eller inom en dynamisk miljö.
- den specifika instans av miljön där referensen löses. En miljö är en runtime-ordbok som mappar symboler till bindningar. Varje typ av referens använder sin egen typ av miljö. Referenser till lexikaliska variabler löses i en lexikal miljö, et cetera. 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 refererar till måste Common Lisp-programmeraren veta vilken typ av referens som uttrycks, vilken typ av räckvidd den använder om det är en variabel referens (dynamisk kontra lexikal räckvidd), och även körtidssituationen: i vilken miljö är referensen löst, var infördes bindningen i miljön, et cetera.
Typer 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. Referenser till den typen slår upp det i denna globala miljö.
Dynamisk
En typ av miljö i Common Lisp är den dynamiska miljön. Bindningar som etablerats i den här miljön har en dynamisk omfattning, vilket innebär att en bindning etableras i början av exekveringen av någon konstruktion, till exempel ett låtblock, och
försvinner när den konstruktionen slutfört exekvering: dess livslängd är bunden till den dynamiska aktiveringen och deaktiveringen av ett block. En dynamisk bindning är dock inte bara synlig inom det blocket; det är också synligt för alla funktioner som anropas från det blocket. Denna typ av synlighet är känd som obestämd räckvidd. Bindningar som uppvisar dynamisk omfattning (livstid kopplad till aktivering och deaktivering av ett block) och obestämd omfattning (synliga för alla funktioner som anropas från det blocket) sägs ha dynamisk omfattning.
Common Lisp har stöd för dynamiskt omfångade variabler, som även kallas specialvariabler. Vissa andra typer av bindningar är också nödvändigtvis dynamiskt omfångade, såsom omstarter och catch-taggar. Funktionsbindningar kan inte omfångas dynamiskt med hjälp av flet
(som endast tillhandahåller funktionsbindningar med lexikalt omfattning), men funktionsobjekt (ett objekt på första nivån i Common Lisp) kan tilldelas dynamiskt omfångade variabler, bindas med let in
dynamiskt omfång, sedan anropas med funcall
eller ANSÖK
.
Dynamiskt omfång är extremt användbart eftersom det lägger till referenstydlighet och disciplin till globala variabler . Globala variabler är ogillade inom datavetenskap som potentiella felkällor, eftersom de kan ge upphov till ad-hoc, hemliga kommunikationskanaler mellan moduler som leder till oönskade, överraskande interaktioner.
I Common Lisp beter sig en specialvariabel som bara har en toppnivåbindning 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å toppnivå. Slarvig ersättning av värdet på en global variabel är kärnan i buggar som orsakas av användningen 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 att "binda om" variabeln. Genom att binda en variabel med dynamisk omfattning skapas tillfälligt en ny minnesplats för den variabeln och associerar namnet med den platsen. Medan den bindningen är i kraft hänvisar alla referenser till den variabeln till den nya bindningen; den tidigare bindningen ä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 kapslas.
I Common Lisp-implementeringar som stöder multithreading är dynamiska omfång specifika för varje exekveringstråd. Därför fungerar speciella variabler som en abstraktion för lokal lagring av trådar. Om en tråd binder om en speciell 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 den bindningen. Om varje tråd binder någon speciell variabel *x*
, beter sig *x*
som trådlokal lagring. Bland trådar som inte binder om *x*
, beter sig den som en vanlig global: alla dessa trådar hänvisar till samma toppnivåbindning av *x*
.
Dynamiska variabler kan användas för att utöka exekveringskontexten med ytterligare kontextinformation som implicit skickas 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 orelaterade kod, som helt enkelt inte kan utökas med extra parametrar för att skicka ytterligare data. En situation som denna kräver vanligtvis en global variabel. Den globala variabeln måste sparas och återställas, så att schemat inte bryts under rekursion: dynamisk variabel ombindning tar hand om detta. Och den variabeln måste göras trådlokal (annars måste en stor mutex användas) så att schemat inte bryts under trådar: dynamiska scope-implementationer kan också ta hand om detta.
I Common Lisp-biblioteket finns det många vanliga specialvariabler. Till exempel lagras alla standard I/O-strömmar i toppnivåbindningarna för välkända specialvariabler. Standardutgångsströmmen lagras i *standardutgång*.
Antag att en funktion foo skriver till standardutdata:
( defun foo () ( format t "Hej världen") )
För att fånga dess utdata i en teckensträng kan *standardoutput* bindas till en strängström och anropas:
( med-utgång-till-sträng ( *standard-utgång* ) ( foo ))
-> "Hej världen" ; samlad utdata returneras som en sträng
Lexikalisk
Common Lisp stöder lexikaliska miljöer. Formellt har bindningarna i en lexikal miljö lexikal räckvidd och kan ha antingen en obestämd utsträckning eller dynamisk utsträckning, beroende på typen av namnutrymme. Lexikal räckvidd innebär att synligheten fysiskt begränsas till det block där bindningen är etablerad. Referenser som inte är textuellt (dvs. lexikalt) inbäddade i det blocket ser helt enkelt inte den bindningen.
Taggarna i en TAGBODY har lexikal räckvidd. 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 sin exekvering, eftersom de har dynamisk utsträckning. Om det kodblocket matas in igen genom anropet av en lexikal stängning är det ogiltigt för den stängningens brödtext att försöka överföra kontrollen till en tagg via GO:
( defvar *stashed* ) ;; kommer att hålla en funktion ( tagbody ( setf *stashed* ( lambda () ( go some-label ))) ( go end-label ) ;; hoppa över (skriv ut "Hej") någon etikett ( skriv ut "Hej" ) slut- etikett ) -> NIL
När TAGBODY exekveras, utvärderar den först setf-formuläret som lagrar en funktion i den speciella variabeln *stashed*. Sedan överför (gå till slutetiketten) kontrollen till slutetiketten och hoppar över koden (skriv ut "Hej"). Eftersom ändetiketten är i slutet av etikettkroppen, avslutas etikettkroppen, vilket ger NIL. Antag att den tidigare ihågkomna funktionen nu kallas:
( funcall *stashed* ) ;; Fel!
Denna situation är felaktig. En implementerings svar är ett feltillstånd som innehåller meddelandet "GO: tagbody för taggen SOME-LABEL har redan lämnats". Funktionen försökte utvärdera (go some-label), som är lexikalt inbäddad i taggkroppen, och löser sig till etiketten. Emellertid körs inte taggkroppen (dess omfattning har upphört), så kontrollöverföringen kan inte ske.
Lokala funktionsbindningar i Lisp har lexical scope och variabla bindningar har också lexical scope som standard. Till skillnad från GO-etiketter har båda dessa obestämd omfattning. När en lexikal funktion eller variabelbindning etableras, fortsätter den bindningen att existera så länge som referenser till den är möjliga, även efter att konstruktionen som fastställde att bindningen har upphört. Referenser till lexikaliska variabler och funktioner efter att deras etablerande konstruktion upphört är möjliga tack vare lexikaliska stängningar .
Lexikal bindning är standardbindningsläget för Common Lisp-variabler. För en enskild symbol kan den växlas till dynamiskt omfång, antingen genom en lokal deklaration, genom en global deklaration. Det senare kan ske implicit genom användning av en konstruktion som DEFVAR eller DEFPARAMETER. Det är en viktig konvention inom Common Lisp-programmering att speciella (dvs. dynamiskt omfångade) variabler har namn som börjar och slutar med en asterisk sigil *
i det som kallas " hörselkåpskonventionen ". Om den följs skapar denna konvention ett separat namnutrymme för speciella variabler, så att variabler som är avsedda att vara lexikaliska inte av misstag görs speciella.
Lexikalisk omfattning är användbar av flera skäl.
För det första kan referenser till variabler och funktioner kompileras till effektiv maskinkod, eftersom runtime-miljöstrukturen är relativt enkel. I många fall kan den optimeras för att stapla lagring, så att öppna och stänga lexikaliska scopes har minimal omkostnad. Även i de fall där fullständiga stängningar måste genereras är tillgången till stängningens miljö fortfarande effektiv; typiskt sett blir varje variabel en förskjutning till en vektor av bindningar, och så blir en variabelreferens en enkel laddnings- eller lagringsinstruktion med en bas-plus-offset- adresseringsmod .
För det andra ger lexikal räckvidd (kombinerat med obestämd omfattning) upphov till den lexikala stängningen , vilket i sin tur skapar ett helt paradigm av programmering centrerat kring användningen av funktioner som är förstklassiga objekt, vilket är roten till funktionell programmering.
För det tredje, kanske viktigast av allt, även om lexikaliska stängningar inte utnyttjas, isolerar användningen av lexikalisk omfattning programmoduler från oönskade interaktioner. På grund av deras begränsade synlighet är lexikaliska variabler privata. Om en modul A binder en lexikal variabel X, och anropar en annan modul B, kommer referenser till X i B inte av misstag att lösas till X-gränsen i A. B har helt enkelt ingen tillgång till X. För situationer där disciplinerade interaktioner genom en variabel är önskvärt, ger Common Lisp speciella variabler. Specialvariabler tillåter en modul A att sätta upp en bindning för en variabel X som är synlig för en annan modul B, anropad 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 räckvidd .
Makron
Ett makro i Lisp liknar ytligt en funktion i användning. Men snarare än att representera ett uttryck som utvärderas, representerar det en transformation av programmets källkod. Makrot hämtar källan den omger som argument, binder dem till sina parametrar och beräknar en ny källform. Denna nya form kan också använda ett makro. Makroexpansionen upprepas tills det nya källformuläret 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: slingkonstruktioner, grenkonstruktioner)
- scoping och bindande konstruktioner
- förenklad syntax för komplex och upprepad källkod
- toppnivådefinierande former med biverkningar vid kompilering
- datadriven programmering
- inbäddade domänspecifika språk (exempel: SQL , HTML , Prolog )
- implicita slutförandeformulär
Olika vanliga Common Lisp-funktioner måste också implementeras som makron, till exempel:
- standard
setf
-abstraktion, för att tillåta anpassade kompileringstidsexpansioner av uppdrags-/åtkomstoperatörer -
with-accessors
,with-slots
,with-open-file
och andra liknandeMED
makron - Beroende på implementering,
om
ellervillkor
är ett makro byggt på den andra, den speciella operatören;när
ochom inte
består av makron - Det kraftfulla
slingdomänspecifika
språket
Makron definieras av defmacro -makrot. Den speciella operatorn makrolet tillåter definition av lokala (lexikalt omfångade) 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 utökar 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 något programmeringsspråk." Hoyte ger flera exempel på iterativ utveckling av makron.
Exempel med användning av ett makro för att definiera en ny kontrollstruktur
Makron tillåter Lisp-programmerare att skapa nya syntaktiska former i språket. En typisk användning är att skapa nya kontrollstrukturer. Exempelmakrot tillhandahåller en tills
looping-konstruktion. Syntaxen är:
(tills provformuläret*)
Makrodefinitionen för tills :
( defmacro tills ( test &body body ) ( låt (( start-tag ( gensym "START" )) ( end-tag ( gensym "END" ))) ` ( tagbody , start-tag ( när , test ( go , end- tag )) ( progn ,@ body ) ( go , start-tag ) , end-tag )))
tagbody är en primitiv Common Lisp specialoperator som ger möjlighet att namnge taggar och använda go -formuläret för att hoppa till dessa taggar. Backquote ` tillhandahåller en notation som tillhandahåller kodmallar, där värdet av formulär som föregås av ett kommatecken fylls i. Formulär som föregås av komma och at-tecken skarvas in. Tagbody -formuläret testar slutvillkoret. Om villkoret är sant, hoppar det till sluttaggen. Annars exekveras den angivna kroppskoden och sedan hoppar den till starttaggen.
Ett exempel på att använda ovanstående till makro:
0
( tills ( = ( slumpmässigt 10 ) ) ( skrivrad "Hej" ) )
Koden kan utökas med funktionen macroexpand-1 . Expansionen för exemplet ovan ser ut så här:
( TAGBODY #:START1136 ( NÄR ( ZEROP ( RANDOM 10 )) ( GO #:END1137 )) ( PROGN ( WRITE-LINE "hej" )) ( GO #:START1136 ) #:END1137 )
är värdet på variabeltestet ( = (slumpmässigt 10) 0) och värdet på variabelkroppen är ( (skrivrad "Hej")) . Kroppen är en lista över former.
Symboler förstoras vanligtvis automatiskt. Expansionen använder TAGBODY med två etiketter. Symbolerna för dessa etiketter beräknas av GENSYM och är inte inbyggda i något paket. Två go- formulär använder dessa taggar för att hoppa till. Eftersom tagbody är en primitiv operator i Common Lisp (och inte ett makro), kommer den inte att utökas till något annat. Det utökade formuläret använder när- makrot, som också kommer att utökas. Att helt expandera en källform kallas kodvandring .
I den helt expanderade ( gående ) formen ersätts när- formen med den primitiva om :
( TAGBODY #:START1136 ( IF ( ZEROP ( RANDOM 10 )) ( PROGN ( GO #:END1137 )) NIL ) ( PROGN ( WRITE-LINE "hej" )) ( GO #:START1136 )) #:END1137 )
Alla makron måste expanderas 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 dessa. Dessa funktioner anropas innan utvärderaren eller kompilatorn för att producera den slutliga källkoden. Makron skrivs i normal Common Lisp och kan använda vilken Common Lisp (eller tredjeparts) som helst som är tillgänglig.
Variabel fångst och skuggning
Vanliga Lisp-makro är kapabla till vad som vanligtvis kallas variabel capture , där symboler i makroexpansionskroppen sammanfaller med dem i anropssammanhanget, vilket gör att programmeraren kan skapa makron där olika symboler har speciell betydelse. Termen variabelfångst är något missvisande, eftersom alla namnområden är sårbara för oönskad infångning, inklusive operatören och funktionen namnutrymme, tagkroppsetiketten namnutrymme, catch-tagg, villkorshanterare och omstart av namnutrymmen.
Variabel insamling kan introducera 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 makroskrivaren antog kommer att lösa i en global namnrymd, men koden där makrot expanderas råkar ge en lokal, skuggande definition som stjäl den referensen. Låt detta kallas typ 1-fångst.
- Det andra sättet, typ 2-infångning, är precis tvärtom: några av makrots argument är bitar av kod som tillhandahålls av makroanroparen, och dessa bitar av kod är skrivna så att de gör referenser till omgivande bindningar. Makrot infogar dock dessa kodbitar i en expansion som definierar sina egna bindningar som av misstag fångar några av dessa referenser.
Schema-dialekten av Lisp tillhandahåller ett makro-skrivsystem som ger referenstransparensen som eliminerar båda typerna av fångstproblem. Denna typ av makrosystem kallas ibland för "hygieniska", i synnerhet av dess förespråkare (som betraktar makrosystem som inte automatiskt löser detta problem som ohygieniska). [ citat behövs ]
I Common Lisp säkerställs makrohygienen på ett av två olika sätt.
Ett tillvägagångssätt är att använda gensyms: garanterat unika symboler som kan användas i en makroexpansion utan hot om att fångas. Användningen av gensyms i en makrodefinition är en manuell syssla, men makron kan skrivas som förenklar instansieringen och användningen av gensyms. Gensyms löser lätt typ 2-infångning, men de är inte tillämpliga på typ 1-infångning 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 skulle kunna 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 negativ 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. Användningen av paket handlar om typ 1 och typ 2 capture.
Paketen löser dock inte typ 1-infångningen av referenser till vanliga Common Lisp-funktioner och -operatorer. 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 synliggörs i andra paket). Medan Common Lisp-bibliotekssymbolerna är externa och ofta importerade till eller görs synliga i användardefinierade paket.
Följande är ett exempel på oönskad infångning i operatörens namnutrymme, som inträffar i expansionen av ett makro:
0 ;; expansion av UNTIL gör liberal användning av DO ( defmacro tills ( expression &body body ) ` ( do ( ) ( , expression ) ,@ body )) ;; macrolet etablerar lexikal operatorbindning för DO ( macrolet (( do ( ... ) ... något annat ... )) ( tills ( = ( slumpmässigt 10 ) ) ( skrivrad "Hej" )))
Makrot tills
kommer att expandera till en form som anrop gör som är avsedd att
referera
till standardmakrot Common Lisp . Men i detta sammanhang do
ha en helt annan innebörd, så tills
kanske inte fungerar korrekt.
Common Lisp löser problemet med skuggning av standardoperatörer och funktioner genom att förbjuda omdefiniering av dem. Eftersom den omdefinierar standardoperatören do
, är det föregående faktiskt ett fragment av icke-överensstämmande Common Lisp, som tillåter implementeringar att diagnostisera och avvisa den.
Konditionssystem
Villkorssystemet ansvarar för undantagshantering i Common Lisp . Det ger villkor , hanterare och omstarter . Villkor är objekt som beskriver en exceptionell situation (till exempel ett fel). Om ett tillstånd signaleras, söker Common Lisp-systemet efter en hanterare för denna tillståndstyp och anropar hanteraren. Hanteraren av information som tillståndstyp och all relevant information som tillhandahålls som en del av tillståndsobjektet, och anropa lämplig omstartsfunktion.
Dessa omstarter, om de inte hanteras av kod, kan presenteras för användare (som en del av ett användargränssnitt, det för en debugger till exempel), så att användaren kan välja och anropa en av de tillgängliga omstarterna. Eftersom villkorshanteraren anropas i samband med felet (utan att avveckla stacken), är fullständig felåterställning möjlig i många fall, där andra undantagshanteringssystem redan skulle ha avslutat den aktuella rutinen. Själva debuggern kan också anpassas eller ersättas med den dynamiska variabeln *debugger-hook* .
Kod som hittas i avvecklingsskyddsformulär som slutbehandlare kommer också att exekveras vid behov trots undantaget.
I följande exempel (med Symbolics Genera ) försöker användaren öppna en fil i ett Lisp-funktionstest som anropas från Read-Eval-Print-LOOP ( REPL ), när filen inte finns. Lisp-systemet presenterar fyra omstarter. Användaren väljer Försök ÖPPNA igen med en omstart av ett annat sökväg och anger ett annat sökvägsnamn (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.
Kommando: (test ">zippy>lispm-int.lisp") Fel: Filen hittades inte. För lispm:>zippy>lispm-int.lisp.newest LMFS:OPEN-LOCAL-LMFS-1 Arg 0: #P"lispm:>zippy>lispm-int.lisp.newest" sA, : Försök igen OPEN av lispm:>zippy>lispm-int.lisp.newest sB: Försök igen OPEN med ett annat sökvägsnamn sC, : Återgå till Lisp toppnivå i en TELNET-server sD: Starta om processen TELNET-terminal -> Försök igen ÖPPNA med ett annat sökvägsnamn Använd vilket sökvägsnamn istället [default lispm:>zippy>lispm-int.lisp.newest]: lispm:>zippy>lispm -init.lisp.newest ...programmet fortsätter
Common Lisp Object System (CLOS)
Common Lisp innehåller en verktygslåda för objektorienterad programmering , Common Lisp Object System eller CLOS . Peter Norvig förklarar hur många Design Patterns som är enklare att implementera i 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 att inkluderas i ANSI Common Lisp-standarden, men så småningom antogs CLOS som standardobjektsystemet för Common Lisp. CLOS är ett dynamiskt objektsystem med multipel sändning och multipel arv , och skiljer sig radikalt från OOP-faciliteterna som finns i statiska språk som C++ eller Java . Som ett dynamiskt objektsystem tillåter CLOS ä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 av typen 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 skulle kunna 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 själva CLOS och mer.
Kompilator och tolk
En Lisp-tolk exekverar direkt Lisp-källkoden som tillhandahålls som Lisp-objekt (listor, symboler, siffror, ...) som läses från s-uttryck. En Lisp-kompilator genererar bytekod eller maskinkod från Lisp-källkoden. Common Lisp tillåter både individuella Lisp-funktioner att kompileras i minnet och kompilering av hela filer till externt lagrad kompilerad kod ( fasl -filer).
Flera implementeringar av tidigare Lisp-dialekter gav både en tolk och en kompilator. Tyvärr var semantiken ofta annorlunda. Dessa tidigare Lisps implementerade lexikal scoping i kompilatorn och dynamisk scoping i tolken. Common Lisp kräver att både tolken och kompilatorn använder lexical scoping som standard. Common Lisp-standarden beskriver både tolkens och en kompilators semantik. Kompilatorn kan anropas med funktionen kompilering för enskilda funktioner och med funktionen kompileringsfil för filer. Common Lisp tillåter typdeklarationer och ger sätt att påverka kompilatorns kodgenereringspolicy. För de senare kan olika optimeringskvaliteter ges värden mellan 0 (inte viktigt) och 3 (viktigast): hastighet , utrymme , säkerhet , felsökning och kompileringshastighet .
Det finns också en funktion för att utvärdera Lisp-kod: eval
. eval
tar kod som förberedda 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 Common Lisp-implementationer (som Clozure CL och SBCL) implementerar eval
med sin kompilator. På detta sätt kompileras koden, även om den utvärderas med funktionen eval
.
Filkompilatorn anropas med funktionen compile-file . Den genererade filen med kompilerad kod kallas en fasl (från fast load ) fil. Dessa fasl- filer och även källkodsfiler kan laddas med funktionen laddas in i ett körande Common Lisp-system. Beroende på implementeringen genererar filkompilatorn byte-kod (till exempel för Java Virtual Machine ), C-språkkod (som sedan kompileras med en C-kompilator) eller, direkt, inbyggd 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 interaktiv Common Lisp.
Språket gör en åtskillnad 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 bearbetning vid det önskade steget.
Vissa speciella operatörer tillhandahålls speciellt för att passa interaktiv utveckling; till exempel defvar
endast att tilldela ett värde till den angivna variabeln om den inte redan var bunden, medan defparameter
alltid kommer att utföra tilldelningen. Denna distinktion är användbar när du interaktivt utvärderar, kompilerar och laddar kod i en levande bild.
Vissa funktioner tillhandahålls också för att hjälpa skrivande kompilatorer och tolkar. Symboler består av objekt på första nivån och är direkt manipulerbara med användarkod. Specialoperatorn progv
tillåter att skapa lexikaliska bindningar programmatiskt, medan paket också är manipulerbara. Lisp-kompilatorn är tillgänglig under körning för att kompilera filer eller enskilda funktioner. Dessa gör det enkelt att använda Lisp som en mellankompilator eller tolk för ett annat språk.
Kodexempel
Födelsedag paradox
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 uppenbarligen är 100%, för 2 är den 364/365, etc. ). Svaret är 23.
Enligt konvention omges konstanter i Common Lisp med +-tecken.
( defconstant +year-size+ 365 ) ( defun födelsedag-paradox ( sannolikhet antal personer ) ( låt (( ny-sannolikhet ( * ( / ( - +årsstorlek+ antal personer ) ) +årsstorlek+ ) sannolikhet ))) ( if ( < ny-sannolikhet 0,5 ) ( 1+ antal personer ) ( födelsedag-paradox ny-sannolikhet ( 1+ antal personer )))))
Anropa exempelfunktionen med REPL (Read Eval Print Loop):
CL-USER > (födelsedagsparadox 1.0 1) 23
Sortera en lista med personobjekt
Vi definierar en klassperson och
en metod för att visa namn och ålder på en person. Därefter definierar vi en grupp av personer som en lista över personobjekt
. Sedan itererar vi över den sorterade listan.
( defclass person () (( namn :initarg :name :accessor person-name ) ( age :initarg :age :accessor person-age )) ( :dokumentation "Klassen PERSON med platser NAMN och ÅLDER." ) ) ( defmetod display (( objekt person ) stream ) "Visar ett PERSON-objekt till en utgångsström." ( with-slots ( namn ålder ) objekt ( formatström " ~ a ( ~ a ) " namn ålder ) ) ) ( defparameter *grupp* ( lista ( make-instance 'person :name "Bob" : ålder 33 ) ( make-instance 'person :name "Chris" : ålder 16 ) ( make-instans 'person :name "Ash" :ålder 23 )) "En lista med PERSON-objekt." ) ( dolist ( person ( sortera ( kopieringslista *grupp* ) #' > :nyckel #' person-ålder )) ( visa person *standardutgång* ) ( terpri ))
Den skriver ut de tre namnen med fallande ålder.
Bob (33) Ash (23) Chris (16)
Exponentiera genom att kvadrera
Användning av LOOP-makrot visas:
( defun power ( x n ) ( loop med resultat = 1 medan ( plusp n ) när ( udda n ) gör ( setf resultat ( * resultat x )) gör ( setf x ( * x x ) n ( trunkate n 2 )) slutligen ( returnera resultat )))
Exempel på användning:
CL-USER > ( effekt 2 200 ) 1606938044258990275541962092341162602522202993782792835301376
Jämför med den inbyggda exponentieringen:
CL-USER > ( = ( expt 2 200 ) ( effekt 2 200 )) T
Hitta listan över tillgängliga skal
WITH-OPEN-FILE är ett makro som öppnar en fil och ger en ström. När formuläret kommer tillbaka stängs filen automatiskt. FUNCALL anropar ett funktionsobjekt. LOOP samlar alla linjer som matchar predikatet.
( defun list-matching - lines ( filpredikat ) "Returnerar en lista med rader i filen, för vilka predikatet som tillämpas på raden returnerar T." ( med -öppen-fil ( stream -fil ) ( loop för rad = ( read- linjeström noll noll ) medan linje när ( funcall predikat linje ) samla den ) ) )
Funktionen AVAILABLE-SHELLS anropar ovanstående funktion LIST-MATCHING-LINES med ett sökvägsnamn och en anonym funktion som predikat. Predikatet returnerar sökvägen för ett skal eller NIL (om strängen inte är filnamnet på ett skal).
0
( defun available-shells ( &valfritt ( fil #p"/etc/shells" )) ( list-matching-lines file ( lambda ( line ) ( och ( plusp ( length line )) ( char= ( char line ) #\/ ) ( sökväg ( sträng-höger-trim ' ( #\mellanslag #\tab ) rad ) )))))
Exempelresultat (på Mac OS X 10.6):
CL-USER > ( tillgängliga-skal ) ( #P"/bin/bash" #P"/bin/csh" #P"/bin/ksh" #P"/bin/sh" #P"/bin/tcsh" #P"/bin/zsh" )
Jämförelse med andra Lisps
Common Lisp jämförs oftast med, och kontrasteras till, Scheme — om än bara för att de är de två mest populära Lisp-dialekterna. Scheme är före CL och kommer inte bara från samma Lisp-tradition utan från några av samma ingenjörer – Guy Steele , som Gerald Jay Sussman designade Scheme med, var ordförande för standardkommittén för Common Lisp.
Common Lisp är ett allmänt programmeringsspråk, till skillnad från Lisp-varianter som Emacs Lisp och AutoLISP som är tilläggsspråk inbäddade i särskilda produkter (GNU Emacs respektive AutoCAD). Till skillnad från många tidigare Lisps, använder Common Lisp (som Scheme ) lexikal variabel omfattning som standard för både tolkad och kompilerad kod.
De flesta av Lisp-systemen vars design bidrog till Common Lisp - som ZetaLisp och Franz Lisp - använde dynamiskt omfångade variabler i sina tolkar och lexikalt omfångade variabler i sina kompilatorer. Scheme introducerade enbart användningen av lexikalt omfångade variabler till Lisp; en inspiration från ALGOL 68 . CL stöder även variabler med dynamisk omfattning, men de måste uttryckligen deklareras som "speciella". Det finns inga skillnader i omfattning mellan ANSI CL-tolkare och kompilatorer.
Common Lisp benämns ibland en Lisp-2 och Schema en Lisp-1 , hänvisar till CL:s användning av separata namnutrymmen för funktioner och variabler. (Faktum är att CL har många namnutrymmen, till exempel de för go-taggar, blocknamn och loop
-nyckelord). Det finns en långvarig kontrovers mellan CL och Scheme-förespråkare angående kompromisserna som är involverade i flera namnområden. I Schema är det (i stort sett) nödvändigt att undvika att ge variabler namn som krockar med funktioner; Schemafunktioner har ofta argument som heter lis
, lst
eller lyst
för att inte komma i konflikt med systemfunktionslistan
. Men i CL är det nödvändigt att uttryckligen hänvisa till funktionen namnutrymme när man skickar en funktion som ett argument – vilket också är en vanlig förekomst, som i sorteringsexemplet ovan
.
CL skiljer sig också från Scheme i sin hantering av booleska värden. Schema använder specialvä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, där NIL också står för den tomma listan. I CL behandlas alla icke-NIL-värden som sanna av villkor, till exempel om
, medan i Schema behandlas alla icke-#f-värden som sanna. Dessa konventioner tillåter vissa operatorer på båda språken att fungera både som predikat (besvarar en booleskt värderad fråga) och som returnerar ett användbart värde för vidare beräkning, men i Schema utvärderas värdet '() som är ekvivalent med NIL i Common Lisp till sant i ett booleskt uttryck.
Slutligen kräver Scheme-standarddokumenten tail-call-optimering , vilket CL-standarden inte gör. De flesta CL-implementeringar erbjuder tail-call-optimering, men ofta bara när programmeraren använder ett optimeringsdirektiv. Icke desto mindre gynnar inte vanlig CL-kodningsstil den allestädes närvarande användningen av rekursion som Scheme-stilen föredrar – vad en Scheme-programmerare skulle uttrycka med tail-rekursion, skulle en CL-användare vanligtvis uttrycka med ett iterativt uttryck i do , dolist ,
loop ,
eller (
nyligen ) med iterate
-paketet.
Genomföranden
Se Kategori Common Lisp-implementeringarna .
Common Lisp definieras av en specifikation (som Ada och C ) snarare än av en implementering (som Perl ). Det finns många implementeringar, och standarddetaljområdena där de kan skilja sig åt.
Dessutom tenderar implementeringar att komma med tillägg, som ger funktionalitet som inte täcks av standarden:
- Interaktiv toppnivå (REPL)
- Skräp samling
- Debugger, Stepper och Inspector
- Svaga datastrukturer (hashtabeller)
- Utökningsbara sekvenser
- Utdragbar LOOP
- Tillgång till miljö
- CLOS Meta-object Protocol
- CLOS-baserade utdragbara strömmar
- CLOS-baserat tillståndssystem
- Nätverksströmmar
- Ihållande STÄNGNING
- Unicode-stöd
- Gränssnitt för främmande språk (ofta till C)
- Operativsystems gränssnitt
- Java-gränssnitt
- Trådar och multibearbetning
- Applikationsleverans (applikationer, dynamiska bibliotek)
- Spara bilder
med gratis och öppen källkod har skapats för att stödja tillägg till Common Lisp på ett bärbart sätt, och de finns framför allt i arkiven för Common-Lisp.net och CLOCC (Common Lisp Open Code Collection).
Vanliga Lisp-implementeringar kan använda valfri blandning av inbyggd kodkompilering, bytekodkompilering eller tolkning. Common Lisp har utformats för att stödja inkrementella kompilatorer , filkompilatorer och blockkompilatorer. Standarddeklarationer för att optimera kompilering (såsom funktionsinlining eller typspecialisering) föreslås i språkspecifikationen. De vanligaste Lisp-implementeringarna kompilerar källkod till inbyggd maskinkod . Vissa implementeringar kan skapa (optimerade) fristående applikationer. Andra kompilerar till tolkad bytecode , som är mindre effektiv än inbyggd kod, men underlättar portabilitet av binär kod. Vissa kompilatorer kompilerar Common Lisp-kod till C-kod. Missuppfattningen att Lisp är ett rent tolkat språk beror mest troligt på att Lisp-miljöer tillhandahåller en interaktiv prompt och att koden kompileras en efter en, på ett stegvis sätt. Med Common Lisp används inkrementell kompilering i stor utsträckning.
Vissa Unix - baserade implementeringar ( CLISP , SBCL ) kan användas som ett skriptspråk ; det vill säga anropas av systemet transparent på det sätt som en Perl- eller Unix- skaltolk ä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 möjligheter för applikationsleverans.
- Liquid Common Lisp
- kallades tidigare Lucid Common Lisp. Endast underhåll, inga nya releaser.
- 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 möjligheter för applikationsleverans.
- mocl
- för iOS, Android och macOS.
- Öppna Genera
- för DEC Alpha.
- Scieneer Common Lisp
- som är designad för högpresterande vetenskaplig beräkning.
Fritt omdistribuerbara 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 tillåter åtkomst till Java-bibliotek från CL. Det var tidigare bara en del av Armed Bear J Editor.
- Clasp
- En LLVM-baserad implementering som sömlöst samverkar med C++-bibliotek. Körs på flera Unix- och Unix-liknande system (inklusive macOS ).
- CLISP
- En bytekod-kompilerande implementering, portabel 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ällkodsgaffel 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 det 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örväxling med öppen källkodsversionen av Macintosh Common Lisp.
- CMUCL
- Ursprungligen från Carnegie Mellon University , nu underhållen som fri programvara med öppen källkod av en grupp volontärer. CMUCL använder en snabb kompilator för inbyggd kod. Den är tillgänglig på Linux och BSD för Intel x86; Linux för Alpha; macOS för Intel x86 och PowerPC; och Solaris, IRIX och HP-UX på sina inhemska plattformar.
- Corman Common Lisp
- för Microsoft Windows. I januari 2015 publicerades Corman Lisp under MIT-licens.
- Embeddable Common Lisp (ECL)
- ECL inkluderar en bytekodtolkare och kompilator. Den kan också kompilera Lisp-kod till maskinkod via en C-kompilator. ECL kompilerar sedan Lisp-koden 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)
- GNU - projektets Lisp-kompilator. Ännu inte helt ANSI-kompatibel, GCL är dock implementeringen av valet 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 som kör Mac OS X är öppen källkod. RMCL (baserat på MCL 5.2) körs på Intel-baserade Apple Macintosh-datorer med hjälp av den binära översättaren Rosetta från Apple.
- ManKai Common Lisp (MKCL)
- En gren av ECL . MKCL betonar tillförlitlighet, stabilitet och övergripande kodkvalitet genom ett kraftigt omarbetat, inbyggt flertrådigt runtime-system. På Linux har MKCL ett helt POSIX-kompatibelt runtime-system.
- 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), som tillåter blandad språkprogrammering. För alla är implementeringsspråket POP-11, som kompileras inkrementellt. Den har också en integrerad Emacs- liknande editor som kommunicerar med kompilatorn.
- Steel Bank Common Lisp (SBCL)
- En filial 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å de plattformar som CMUCL gör, förutom HP/UX; dessutom körs den på Linux för AMD64, PowerPC, SPARC, MIPS, Windows x86 och har experimentellt stöd för att köra på Windows AMD64. SBCL använder inte en tolk som standard; alla uttryck kompileras till inbyggd kod om inte användaren slår på tolken. SBCL-kompilatorn genererar snabb inbyggd kod enligt en tidigare version av The Computer Language Benchmarks Game .
- Ufasoft Common Lisp
- -port av CLISP 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 Schema för BBN Butterfly -multiprocessordatorn
- CLICC
- en Common Lisp to C-kompilator
- CLOE
- Common Lisp för PCs av Symbolics
- Codemist Common Lisp
- som används för den kommersiella version av datoralgebrasystemet Axiom
- ExperCommon Lisp
- en tidig implementering för Apple Macintosh av ExperTelligence
- Golden Common Lisp
- en implementering för PC 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 Common Lisp-implementering.
- L
- en liten version av Common Lisp för inbyggda system utvecklade av IS Robotics, nu tillhandahåller iRobot
- Lisp Machines (från Symbolics , TI och Xerox)
- implementeringar av Common Lisp utöver deras inhemska Lisp-dialekt (Lisp Machine Lisp eller Interlisp). CLOS var också tillgängligt. Symbolics tillhandahåller 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 av Allegro CL
- Star Sapphire Common LISP
- en implementering för PC
- SubL
- en variant av Common Lisp som används för implementering av det Cyc kunskapsbaserade systemet
- Top Level Common Lisp
- en tidig implementering för samtidig körning
- WCL
- en implementering av ett delat bibliotek
- VAX Common Lisp
- Digital Equipment Corporations implementering som kördes på VAX -system som kör VMS eller ULTRIX
- XLISP
- en implementering skriven av David Betz
Ansökningar
Common Lisp används för att utveckla forskningsapplikationer (ofta inom artificiell intelligens ), för snabb utveckling av prototyper eller för utplacerade applikationer.
Common Lisp används i många kommersiella tillämpningar, inklusive Yahoo! Webbhandelswebbplats för butik, som ursprungligen involverade Paul Graham och som 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ångvarigt projekt för att skapa ett kunskapsbaserat system som ger en enorm mängd sunt förnuft.
- motor för affärsregler i realtid
- Genworks GDL, baserat på Gendl-kärnan med öppen källkod.
- Utvecklingsmiljön för videospelsserien Jak och Daxter , utvecklad av Naughty Dog .
- ITA Softwares lågprissökmotor, som används av resewebbplatser 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 Gollums ansikte i filmen Sagan om ringen: De två tornen .
- Opusmodus är ett musikkompositionssystem baserat på Common Lisp, som används i datorstödd 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 datorstödd komposition och ljudsyntes.
- Piano, en komplett flygplansanalyssvit, 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 kärna grammatikmotor skriven i Common Lisp.
- Dynamic Analysis and Replanning Tool (DART), som ensam sägs ha betalat tillbaka under åren från 1991 till 1995 för alla trettio år av DARPA -investeringar i AI-forskning.
- NASA :s Jet Propulsion Labs " Deep Space 1 ", ett prisbelönt Common Lisp-program för autopilot av rymdskeppet Deep Space One .
- SigLab, en Common Lisp-plattform för signalbehandling som används i 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 Space Telescope, skrivet i Common Lisp.
- Common Lisp har använts för att skapa prototyper av skräpsamlaren 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 Reddits medgrundare Steve Huffman .
Det finns också applikationer med öppen källkod skrivna i Common Lisp, som:
- ACL2 , en fullfjädrad automatiserad teorembevisare 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 datorstödd komposition .
- Pgloader, en dataladdare för PostgreSQL , som skrevs om från Python till Common Lisp.
- Stumpwm , en tangentbordsdriven X11 Window Manager helt skriven i Common Lisp.
Se även
Bibliografi
En kronologisk lista över böcker publicerade (eller på väg att publiceras) om Common Lisp (språket) eller om programmering med Common Lisp (särskilt AI-programmering).
- Guy L. Steele : Common Lisp the Language, 1:a upplagan , 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 : Performance and Evaluation of Lisp Systems , 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 . Webb/PDF Dover reprint (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, 3rd Edition , Addison-Wesley, 1989, ISBN 0-201-08319-1 , Webb
- 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, and 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 , 2nd Edition , Digital Press, 1990, ISBN 1-55558-041-6 , Webb
- 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: The 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 , Webb
- 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: Artificial Intelligence with Common 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: The CLOS Perspective , 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 , tyska, 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 , Webb
- Peter Seibel: Practical Common Lisp , Apress, 2005. ISBN 1-59059-239-5 , Webb
- Doug Hoyte: Let Over Lambda , Lulu.com, 2008, ISBN 1-4357-1275-7 , Webb
- George F. Luger, William A. Stubblefield: AI Algorithms, Data Structures, and Idioms in Prolog, Lisp and Java , Addison Wesley, 2008, ISBN 0-13-607047-7 , PDF
- Conrad Barski: Land of Lisp: Lär dig programmera i Lisp, ett spel i taget! , No Starch Press, 2010, ISBN 1-59327-200-6 , Webb
- Pavel Penev: Lisp Web Tales , Leanpub, 2013, Web
- Edmund Weitz: Common Lisp Recipes , Apress, 2015, ISBN 978-1-484211-77-9 , Webb
- Patrick M. Krusenotto: Funktionale Programmierung und Metaprogrammierung, Interaktiv in Common Lisp , Springer Fachmedien Wiesbaden 2016, ISBN 978-3-658-13743-4 , Webb
externa länkar
- Quicklisp - En mycket populär och högkvalitativ biblioteksansvarig för Common Lisp
- Awesome CL -listan, en kurerad lista över Common Lisp-ramverk och bibliotek.
- The Common Lisp Cookbook , ett samarbetsprojekt.
- CLiki , en Wiki för gratis och öppen källkod Common Lisp-system som körs på Unix-liknande system .
- En av de viktigaste förråden 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 Lisps historia: "Historia" . Common Lisp HyperSpec .
- Common Lisp Quick Reference – en kompakt översikt av Common Lisp-standardspråket.
- Planet Lisp Artiklar om Common Lisp.
- Quickdocs sammanfattar dokumentation och beroendeinformation för många Quicklisp-projekt.
- Artiklar med exempel Lisp (programmeringsspråk) kod
- Klassbaserade programmeringsspråk
- Vanlig Lisp
- Gratis programvara för flera plattformar
- Programvara för flera plattformar
- Dynamiska programmeringsspråk
- Dynamiskt typade programmeringsspråk
- Utökningsbara programmeringsspråk för syntax
- Funktionella språk
- Lisp (programmeringsspråk)
- Lisp programmeringsspråk familj
- Flerparadigm programmeringsspråk
- Objektorienterade programmeringsspråk
- Procedurmässiga programmeringsspråk
- Programmeringsspråk skapade 1984