Emacs Lisp
Paradigm | Funktionell , meta , reflekterande |
---|---|
Familj | Läspa |
Designad av |
Richard Stallman , Guy L. Steele, Jr. |
Utvecklare | GNU-projekt |
Dök först upp | 1985 |
Stabil frisättning | 28.1 / 4 april 2022
|
Maskinskrivningsdisciplin | Dynamisk , stark |
Omfattning | Dynamisk, valfritt lexikal |
Plattform | Emacs |
OS | Cross-plattform |
Licens | GPLv3 |
Filnamnstillägg | .el, .elc, .eln |
Hemsida | |
Influerad av | |
Common Lisp , Maclisp |
Emacs Lisp är en dialekt av programmeringsspråket Lisp som används som skriptspråk av Emacs (en textredigeringsfamilj som oftast förknippas med GNU Emacs och XEmacs ). Den används för att implementera de flesta redigeringsfunktioner som är inbyggda i Emacs, resten skrivs i C , liksom Lisp- tolken . Emacs Lisp kallas också för Elisp , även om det också finns en äldre, obesläktad Lisp-dialekt med det namnet.
Användare av Emacs skriver vanligtvis Emacs Lisp-kod för att anpassa och utöka Emacs. Andra alternativ inkluderar Customize -funktionen som har funnits i GNU Emacs sedan version 20. Customize är skriven i Emacs Lisp och tillhandahåller en uppsättning inställningssidor som låter användaren ställa in alternativ och förhandsgranska deras effekt i den pågående Emacs-sessionen. När användaren sparar sina ändringar skriver Customize helt enkelt den nödvändiga Emacs Lisp-koden till användarens konfigurationsfil , som kan ställas in på en speciell fil som endast Customize använder, för att undvika möjligheten att ändra användarens egen fil.
Emacs Lisp kan också fungera som ett skriptspråk , ungefär som Unix Bourne-skalet eller Perl , genom att anropa Emacs i batchläge . På så sätt kan den anropas från kommandoraden eller via en körbar fil, och dess redigeringsfunktioner, såsom buffertar och rörelsekommandon, är tillgängliga för programmet precis som i normalläget. Inget användargränssnitt visas när Emacs startas i batchläge; det kör helt enkelt det inskrivna skriptet och avslutar, och visar alla utdata från skriptet.
Jämfört med andra Lisp-dialekter
Emacs Lisp är närmast släkt med Maclisp , med visst senare inflytande från Common Lisp . Den stöder imperativa och funktionella programmeringsmetoder . Richard Stallman valde Lisp som tilläggsspråk för sin omskrivning av Emacs (det ursprungliga använda Text Editor and Corrector (TECO) som sitt tilläggsspråk) på grund av dess kraftfulla funktioner, inklusive förmågan att behandla funktioner som data. Även om Common Lisp-standarden ännu inte hade formulerats, Scheme när Stallman skrev om Gosling Emacs till GNU Emacs. Han valde att inte använda den på grund av dess jämförelsevis dåliga prestanda på arbetsstationer (till skillnad från minidatorerna som var Emacs traditionella hem), och han ville utveckla en dialekt som han trodde skulle vara lättare att optimera.
Lisp-dialekten som används i Emacs skiljer sig väsentligt från de mer moderna Common Lisp- och Scheme- dialekterna som används för applikationsprogrammering. En framträdande egenskap hos Emacs Lisp är dess användning av dynamisk snarare än lexikal omfattning som standard. Det vill säga, en funktion kan referera till lokala variabler i det omfång den anropas från, men inte i det omfång där den definierades. Nyligen har det gjorts ett pågående försök att uppdatera koden för att använda lexikal omfattning, av skäl som beskrivs nedan.
1955 | 1960 | 1965 | 1970 | 1975 | 1980 | 1985 | 1990 | 1995 | 2000 | 2005 | 2010 | 2015 | 2020 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
LISP 1, 1.5, LISP 2 (övergiven) | ||||||||||||||
Maclisp | ||||||||||||||
Interlisp | ||||||||||||||
MDL | ||||||||||||||
Lisp Machine Lisp | ||||||||||||||
Schema | R5RS | R6RS | R7RS liten | |||||||||||
NIL | ||||||||||||||
ZIL (Zork Implementation Language) | ||||||||||||||
Franz Lisp | ||||||||||||||
Vanlig Lisp | ANSI standard | |||||||||||||
Le Lisp | ||||||||||||||
MIT Scheme | ||||||||||||||
T | ||||||||||||||
Chez Scheme | ||||||||||||||
Emacs Lisp | ||||||||||||||
AutoLISP | ||||||||||||||
PicoLisp | ||||||||||||||
Gambit | ||||||||||||||
EuLisp | ||||||||||||||
ISLISP | ||||||||||||||
OpenLisp | ||||||||||||||
PLT-schema | Racket | |||||||||||||
GNU Guile | ||||||||||||||
Visual LISP | ||||||||||||||
Clojure | ||||||||||||||
Arc | ||||||||||||||
LFE | ||||||||||||||
Hy |
Exempel
För att förstå logiken bakom Emacs Lisp är det viktigt att komma ihåg att det ligger en betoning på att tillhandahålla datastrukturer och funktioner som är specifika för att göra en mångsidig textredigerare framför implementering av ett allmänt programmeringsspråk. Till exempel kan Emacs Lisp inte enkelt läsa en fil en rad i taget – hela filen måste läsas in i en Emacs-buffert. Emacs Lisp tillhandahåller dock många funktioner för att navigera och ändra bufferttext på en menings-, stycke- eller högre syntaktisk nivå som definieras av lägen.
Här följer ett enkelt exempel på en Emacs-tillägg skriven i Emacs Lisp. I Emacs kan redigeringsområdet delas upp i separata områden som kallas fönster , var och en visar en annan buffert . En buffert är ett område med text som laddas in i Emacs minne (eventuellt från en fil) som kan sparas i ett textdokument.
Användare kan trycka på standard Cx 2- nyckelbindning för att öppna ett nytt fönster. Detta kör Emacs Lisp-funktionen split-window-below
. Normalt, när det nya fönstret visas, visar det samma buffert som det föregående. Anta att vi vill få den att visa nästa tillgängliga buffert. För att göra detta skriver användaren följande Emacs Lisp-kod, antingen i en befintlig Emacs Lisp-källfil eller en tom Emacs-buffert:
( defun my-split-window-func () ( interaktiv ) ( split-window-below ) ( set-window-buffer ( nästa-fönster ) ( annan-buffert ))) ( global-set-key ( kbd "Cx 2 " ) #' my-split-window-func )
Den första satsen, (defun ...)
, definierar en ny funktion, my-split-window-func
, som anropar split-window-below
(den gamla fönsterdelande funktionen), sedan säger till det nya fönstret att visa ett annat (nytt) ) buffert. Den andra satsen, (global-set-key ...)
återbinder nyckelsekvensen "Cx 2" till den nya funktionen.
Detta kan också skrivas med hjälp av funktionen som kallas råd , som låter användaren skapa omslag runt befintliga funktioner istället för att definiera sina egna. Detta har fördelen av att det inte kräver att tangentbindningar ändras och fungerar varhelst den ursprungliga funktionen kallas, samt att det är enklare att skriva men nackdelen med att göra felsökningen mer komplicerad. Av denna anledning råd inte tillåtet i källkoden för GNU Emacs, men om en användare önskar kan rådgivningsfunktionen användas i deras kod för att implementera ovanstående kod enligt följande:
( defadvice split-window-below ( efter my-window-splitting-advice först () aktivera ) ( set-window-buffer ( nästa-fönster ) ( annan-buffert )))
Detta instruerar split-window-below
att exekvera den av användaren tillhandahållna koden när den anropas, efter att ha kört resten av funktionen. Råd kan också specificeras för att exekvera före den ursprungliga funktionen, runt den (bokstavligen linda originalet), eller att villkorligt exekvera den ursprungliga funktionen baserat på resultaten av råden.
Emacs 24.4 ersätter denna defadvice-
mekanism med råd-lägg
, som påstås vara mer flexibel och enklare. Råden ovan skulle kunna implementeras på nytt med det nya systemet som:
( defun switch-to-next-window-in-split () ( set-window-buffer ( next-window ) ( other-buffer ))) ( råd-lägg till 'split-window-below :before #' switch-to -nästa-fönster-i-delat )
Dessa ändringar träder i kraft så snart koden har utvärderats . Det är inte nödvändigt att kompilera om, starta om Emacs eller ens omhasha en konfigurationsfil. Om koden sparas i en Emacs init-fil, kommer Emacs att ladda tillägget nästa gång den startar. Annars måste ändringarna omvärderas manuellt när Emacs startas om.
Källkod
Emacs Lisp-kod lagras i filsystem som vanliga textfiler , enligt konvention med filnamnssuffixet " .el
". Användarens init-fil är ett undantag, som ofta visas som " .emacs
" trots att den utvärderas som vilken Emacs Lisp-kod som helst. Sedan mitten av 1990-talet laddar Emacs även ~/.emacs.el
och ~/.emacs.d/init.el
. Dessutom kan användare ange vilken fil som helst som ska laddas som en konfigurationsfil på kommandoraden, eller uttryckligen ange att ingen konfigurationsfil ska laddas. När filerna är laddade läser och analyserar en tolkkomponent i Emacs-programmet funktionerna och variablerna och lagrar dem i minnet. De är sedan tillgängliga för andra redigeringsfunktioner och för användarkommandon. Funktioner och variabler kan fritt ändras och omdefinieras utan att starta om editorn eller ladda om konfigurationsfilen.
För att spara tid och minnesutrymme laddas mycket av funktionerna i Emacs endast när det behövs. Varje uppsättning valfria funktioner som levereras med Emacs implementeras av en samling Emacs-kod som kallas ett paket eller bibliotek . Till exempel finns det ett bibliotek för att markera nyckelord i programmets källkod, och ett bibliotek för att spela spelet Tetris . Varje bibliotek implementeras med en eller flera Emacs Lisp-källfiler. Bibliotek kan definiera ett eller flera huvudlägen för att aktivera och kontrollera deras funktion.
Emacs-utvecklare skriver vissa funktioner i C. Dessa är primitiver , även kallade inbyggda funktioner eller subrs . Även om primitiver kan anropas från Lisp-kod, kan de bara ändras genom att redigera C-källfilerna och kompilera om. I GNU Emacs är primitiver inte tillgängliga som externa bibliotek; de är en del av Emacs körbara. I XEmacs är runtime-laddning av sådana primitiver möjlig genom att använda operativsystemets stöd för dynamisk länkning . Funktioner kan skrivas som primitiva eftersom de behöver tillgång till externa data och bibliotek som inte annars är tillgängliga från Emacs Lisp, eller för att de kallas tillräckligt ofta för att den jämförande hastigheten för C kontra Emacs Lisp gör en värdefull skillnad.
Men eftersom fel i C-kod lätt kan leda till segmenteringsöverträdelser eller till mer subtila buggar, som kraschar redigeraren, och eftersom att skriva C-kod som interagerar korrekt med Emacs Lisp garbage collector är felbenägen, är antalet funktioner implementerade som primitiva hålls till ett nödvändigt minimum.
Byte kod
Byte-kompilering kan få Emacs Lisp-kod att exekvera snabbare. Emacs innehåller en kompilator som kan översätta Emacs Lisp-källfiler till en speciell representation som kallas bytecode . Emacs Lisp bytecode-filer har filnamnssuffixet " .elc
". Jämfört med källfiler laddas bytekodfiler snabbare, tar mindre utrymme på disken, använder mindre minne när de laddas och körs snabbare.
Bytekod körs fortfarande långsammare än primitiver, men funktioner som laddas som bytekod kan enkelt ändras och laddas om. Dessutom är bytekodfiler plattformsoberoende. Standard Emacs Lisp-koden som distribueras med Emacs laddas som bytekod, även om de matchande källfilerna vanligtvis också tillhandahålls för användarens referens. Användarförsedda tillägg är vanligtvis inte bytekompilerade, eftersom de varken är lika stora eller beräkningskrävande.
Språkfunktioner
Noterbart är att "cl-lib"-paketet implementerar en ganska stor delmängd av Common Lisp . Det här paketet ersätter ett tidigare "cl"-paket, som skulle skriva över befintliga Emacs Lisp-funktionsdefinitioner med de som liknar dem som finns i Common Lisp. Paketet "cl-lib", å andra sidan, följer Emacs Lisp stil riktlinjer närmare och prefix varje funktion och makro som det definierar med "cl-" (t.ex. cl- defun
, som inte står i konflikt med namnet på inbyggd defun
), undviker de oväntade beteendeförändringarna som kan inträffa närhelst "cl"-paketet laddades.
Emacs Lisp (till skillnad från vissa andra Lisp-implementationer) gör inte tail-call-optimering . Utan detta svansrekursioner så småningom leda till stackoverflow .
Apel-biblioteket hjälper till att skriva bärbar Emacs Lisp-kod, med hjälp av polysylabi-plattformsbryggan.
Emacs Lisp är en Lisp-2 vilket betyder att den har en funktion namnrymd som är skild från namnrymden den använder för andra variabler.
Från dynamisk till lexikal omfattning
Liksom MacLisp använder Emacs Lisp dynamic scope , och erbjuder statisk (eller lexical) som ett alternativ från version 24. Det kan aktiveras genom att ställa in filen lokal variabel lexical-binding
. Innan det här alternativet lades till kunde man använda lexical-let-
makrot från det (nu utfasade) "cl"-paketet för att ge effektiv lexikal omfattning.
I dynamisk scoping, om en programmerare deklarerar en variabel inom räckvidden för en funktion, är den tillgänglig för subrutiner som anropas från den funktionen. Ursprungligen var detta tänkt som en optimering ; lexikal omfattning var fortfarande ovanlig och med osäker prestanda. "Jag frågade RMS när han implementerade emacs lisp varför det var dynamiskt scoped och hans exakta svar var att lexical scope var för ineffektivt." Dynamisk omfattning var också tänkt att ge större flexibilitet för användaranpassningar. Dynamisk scoping har dock flera nackdelar. För det första kan det lätt leda till buggar i stora program, på grund av oavsiktliga interaktioner mellan variabler i olika funktioner. För det andra är åtkomst till variabler under dynamisk omfattning i allmänhet långsammare än under lexikal omfattning.
Se även
externa länkar
- Officiell webbplats , GNU Project