Scheme är en minimalistisk dialekt av Lisp-programmeringsspråket, utformad för att underlätta en funktionell programmeringsstil samtidigt som den främjar en enkel och ren syntax. Den kännetecknas av sin användning av parenteser, ett kraftfullt makrosystem och en stark betoning på rekursion och förstklassiga procedurer. Språket uppmuntrar ett funktionellt programmeringsparadigm och stöder flera programmeringstekniker, inklusive funktionell, imperativ och logisk programmering.
Scheme skapades på 1970-talet av Gerald Jay Sussman och Guy L. Steele Jr. vid Massachusetts Institute of Technology (MIT). Det utvecklades som ett försök att förenkla och förbättra det ursprungliga Lisp-språket, som hade blivit komplext över tid. Motivationen bakom Scheme var att skapa ett språk som skulle vara lättare att implementera och undervisa i, samtidigt som det fortfarande var tillräckligt kraftfullt för att uttrycka komplexa idéer.
Under åren har Scheme genomgått olika revideringar och standardiseringsinsatser. De mest anmärkningsvärda av dessa standarder är RnRS (Revisedn Reports on the Algorithmic Language Scheme), som formaliserade språket och dess funktioner. Scheme-gemenskapen har sedan dess fortsatt att utveckla språket, vilket har lett till nyare standarder som R6RS och R7RS, som introducerade nya funktioner och förbättringar.
I dagsläget är Scheme fortfarande populärt inom akademiska miljöer, särskilt inom datavetenskaplig utbildning, på grund av sin elegans och rena syntax. Dess påverkan kan ses i många moderna programmeringsspråk och paradigmer. Scheme är ofta förknippat med den funktionella programmeringsgemenskapen och har inspirerat språk som Clojure och Racket, som har byggt vidare på dess principer och utökat dess kapabiliteter.
Scheme använder en helt parentesbaserad syntax där kod skrivs i prefixnotation; till exempel skrivs en additionsoperation som (+ 1 2)
.
Funktioner i Scheme är förstklassiga medborgare, vilket innebär att de kan skickas som argument eller returneras från andra funktioner. Exempel:
(define (make-adder x)
(lambda (y) (+ x y)))
(define add5 (make-adder 5))
(add5 10) ; returnerar 15
Scheme stöder tail call optimization, vilket gör att funktioner kan återanvända den aktuella stackramen för rekursiva anrop som sker i tail-position, vilket förhindrar stacköverflöd.
Scheme tillåter användning av fortsättningar, vilket gör det möjligt för programmerare att fånga det aktuella tillståndet av beräkningen och manipulera kontrollflödet:
(call-with-current-continuation
(lambda (exit)
(exit 'done)))
Scheme har ett kraftfullt makrosystem som gör det möjligt för programmerare att skapa syntaktiska utvidgningar. Ett enkelt makro kan definieras som följer:
(define-syntax my-if
(syntax-rules ()
((_ test then else)
(if test then else))))
Scheme stöder dataabstraktion genom strukturer som listor, par och högre ordningens funktioner, vilket möjliggör effektiv manipulation av data.
Scheme använder lexikalt skop, där skopet för en variabel bestäms av dess fysiska plats i källkoden. Detta leder till förutsägbart beteende när det gäller variabelbindningar.
Scheme är dynamiskt typat, vilket gör att variabler kan hålla värden av vilken typ som helst utan behov av explicita typdeklarationer.
Som en Lisp-dialekt är Scheme optimerad för listbearbetning, vilket gör det enkelt att utföra operationer på listor:
(define my-list (list 1 2 3 4))
(car my-list) ; returnerar 1
(cdr my-list) ; returnerar (2 3 4)
Scheme-funktioner kan definieras rekursivt med tail-position för att optimera minnesanvändning och prestanda. Till exempel:
(define (factorial n)
(define (fact-helper n acc)
(if (zero? n)
acc
(fact-helper (- n 1) (* n acc))))
(fact-helper n 1))
Scheme-applikationer kan vanligtvis byggas med hjälp av den valda implementationens körmiljö. Till exempel, i Racket kan du använda kommandoradsverktyget racket
för att köra .rkt
-filer eller kompilera dem till körbara filer.
Flera kompilatorer och tolkar finns tillgängliga för Scheme, inklusive:
Scheme används i stor utsträckning inom akademin för att undervisa programmeringsprinciper och som ett verktyg för forskning inom datavetenskap. Det har tillämpningar inom artificiell intelligens, språkdesign och skriptning, samt inom olika områden som kräver symbolisk beräkning eller komplex datamanipulation.
Båda språken stöder en funktionell programmeringsstil, men Python betonar läsbarhet och enkelhet, medan Scheme fokuserar på kraftfulla och koncisa uttryck. Schemes parentestunga syntax kan ses som ett hinder för nybörjare, medan Pythons indenteringsbaserade syntax generellt är mer tillgänglig.
JavaScript stöder också funktionell programmering och har förstklassiga funktioner. Men JavaScript har ett prototypbaserat objektsystem, medan Scheme förlitar sig på funktionella paradigmer. Schemes makrosystem erbjuder kapabiliteter som inte finns i JavaScript.
C är ett lågnivå, statiskt typat språk som är utformat för systemprogrammering, medan Scheme är hög-nivå och dynamiskt typat. C fokuserar på prestanda och hårdvarunivåmanipulation, medan Scheme betonar abstraktion och teoretiska aspekter av beräkning.
Båda språken har sina rötter i funktionell programmering. Haskell använder ett mer strikt typ-system och stöder lat evaluering, medan Schemes dynamiska typning och ivriga evaluering möjliggör mer flexibel programmering på bekostnad av viss prestanda.
Ruby är ett objektorienterat programmeringsspråk som blandar funktionella programmeringsfunktioner, medan Scheme är rent funktionellt. Rubys syntax är mer utförlig, medan Schemes enkelhet kommer från dess minimalistiska design.
Översättningen av Scheme-kod till andra språk kan underlättas av verktyg som förstår både Scheme-syntax och målspråket. Några användbara verktyg för käll-till-käll kodöversättning inkluderar:
Chicken Scheme tillhandahåller en kompilator som kan översätta Scheme-kod till C, vilket gör det möjligt att utnyttja C-bibliotek och skapa effektiva körbara filer.
Racket, en avledning av Scheme, har inbyggda funktioner för att transformera och kompilera kod till JavaScript, vilket gör det enklare att distribuera webbapplikationer.
Gambit Scheme kan kompilera Scheme-kod till C och inbyggda körbara filer, vilket ger effektiva översättningsalternativ för prestandakritiska applikationer.