Scheme er en minimalistisk dialekt af Lisp-programmeringssproget, designet til at lette en funktionel programmeringsstil, samtidig med at det fremmer en simpel og ren syntaks. Det er kendetegnet ved sin brug af parenteser, et kraftfuldt makrosystem og en stærk vægt på rekursion og førsteklasses procedurer. Sproget opfordrer til et funktionelt programmeringsparadigme og understøtter flere programmeringsteknikker, herunder funktionel, imperativ og logisk programmering.
Scheme blev skabt i 1970'erne af Gerald Jay Sussman og Guy L. Steele Jr. ved Massachusetts Institute of Technology (MIT). Det blev udviklet som et forsøg på at forenkle og forbedre det oprindelige Lisp-sprog, som var blevet komplekst over tid. Motivation bag Scheme var at skabe et sprog, der ville være lettere at implementere og undervise i, samtidig med at det stadig var kraftfuldt nok til at udtrykke komplekse ideer.
I løbet af årene har Scheme gennemgået forskellige revisioner og standardiseringsindsatser. De mest bemærkelsesværdige af disse standarder er RnRS (Revisedn Reports on the Algorithmic Language Scheme), som formaliserede sproget og dets funktioner. Scheme-fællesskabet har siden fortsat med at udvikle sproget, hvilket har ført til nyere standarder som R6RS og R7RS, som introducerede nye funktioner og forbedringer.
I øjeblikket er Scheme stadig populært i akademiske miljøer, især inden for datalogiuddannelse, på grund af sin elegance og rene syntaks. Dets indflydelse kan ses i mange moderne programmeringssprog og paradigmer. Scheme er ofte forbundet med det funktionelle programmeringssamfund og har inspireret sprog som Clojure og Racket, som har bygget videre på dets principper og udvidet dets kapabiliteter.
Scheme bruger en fuldt parentetisk syntaks, hvor kode skrives i præfiksnotation; for eksempel skrives en additionsoperation som (+ 1 2)
.
Funktioner i Scheme er førsteklasses borgere, hvilket betyder, at de kan videregives som argumenter eller returneres fra andre funktioner. Eksempel:
(define (make-adder x)
(lambda (y) (+ x y)))
(define add5 (make-adder 5))
(add5 10) ; returnerer 15
Scheme understøtter tail call optimering, hvilket gør det muligt for funktioner at genbruge den nuværende stakramme til rekursive kald, der forekommer i tail-position, hvilket forhindrer stakoverløb.
Scheme tillader brugen af fortsættelser, hvilket gør det muligt for programmører at fange den nuværende tilstand af beregningen og manipulere kontrolflowet:
(call-with-current-continuation
(lambda (exit)
(exit 'done)))
Scheme har et kraftfuldt makrosystem, der gør det muligt for programmører at skabe syntaktiske udvidelser. En simpel makro kan defineres som følger:
(define-syntax my-if
(syntax-rules ()
((_ test then else)
(if test then else))))
Scheme understøtter dataabstraktion gennem strukturer som lister, par og højere ordens funktioner, hvilket muliggør effektiv manipulation af data.
Scheme anvender leksikalsk scoping, hvor omfanget af en variabel bestemmes af dens fysiske placering i kildekoden. Dette fører til forudsigeligt adfærd vedrørende variabelbindinger.
Scheme er dynamisk typet, hvilket tillader variabler at holde værdier af enhver type uden behov for eksplicitte typeerklæringer.
Som en Lisp-dialekt er Scheme optimeret til listebehandling, hvilket gør det nemt at udføre operationer på lister:
(define my-list (list 1 2 3 4))
(car my-list) ; returnerer 1
(cdr my-list) ; returnerer (2 3 4)
Scheme-funktioner kan defineres rekursivt med tail-position for at optimere hukommelsesbrug og ydeevne. For eksempel:
(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 generelt bygges ved hjælp af den valgte implementerings runtime-miljø. For eksempel, i Racket kan du bruge kommandolinjeværktøjet racket
til at køre .rkt
-filer eller kompilere dem til eksekverbare filer.
Flere kompilatorer og fortolkere er tilgængelige for Scheme, herunder:
Scheme anvendes bredt i akademia til undervisning i programmeringsprincipper og som et værktøj til forskning inden for datalogi. Det har anvendelser inden for kunstig intelligens, sprogdesign og scripting, samt i forskellige domæner, der kræver symbolsk beregning eller kompleks datamanipulation.
Begge sprog understøtter en funktionel programmeringsstil, men Python lægger vægt på læsbarhed og enkelhed, mens Scheme fokuserer på kraftfulde og præcise udtryk. Schemes parentes-tunge syntaks kan ses som en barriere for begyndere, mens Python's indrykningsbaserede syntaks generelt er mere tilgængelig.
JavaScript understøtter også funktionel programmering og har førsteklasses funktioner. Dog har JavaScript et prototype-baseret objektsystem, mens Scheme er afhængig af funktionelle paradigmer. Schemes makrosystem tilbyder kapabiliteter, der ikke er til stede i JavaScript.
C er et lavniveau, statisk typet sprog designet til systemprogrammering, mens Scheme er højniveau og dynamisk typet. C fokuserer på ydeevne og hardware-niveau manipulation, mens Scheme lægger vægt på abstraktion og teoretiske aspekter af beregning.
Begge sprog er rodfæstet i funktionel programmering. Haskell bruger et mere stift typesystem og understøtter lazy evaluation, mens Schemes dynamiske typing og eager evaluation tillader mere fleksibel programmering på bekostning af noget ydeevne.
Ruby er et objektorienteret programmeringssprog, der blander funktionelle programmeringsfunktioner, mens Scheme er rent funktionelt. Rubys syntaks er mere udførlig, mens Schemes enkelhed kommer fra dets minimalistiske design.
Oversættelsen af Scheme-kode til andre sprog kan lettes af værktøjer, der forstår både Scheme-syntaks og målsproget. Nogle nyttige værktøjer til kilde-til-kilde kodeoversættelse inkluderer:
Chicken Scheme leverer en kompilator, der kan oversætte Scheme-kode til C, hvilket gør det muligt at udnytte C-biblioteker og skabe effektive eksekverbare filer.
Racket, en afledning af Scheme, har indbyggede kapabiliteter til at transformere og kompilere kode til JavaScript, hvilket gør det lettere at implementere webapplikationer.
Gambit Scheme kan kompilere Scheme-kode til C og native eksekverbare filer, hvilket giver effektive oversættelsesmuligheder til ydeevne-kritiske applikationer.