> (* (+ 8 1) 3) Pas + toe op waarde van 8 en waarde van 1 Resultaat is 9 Pas * toe op 9 en waarde van 3 Resultaat is 27 27Er zijn ook expressies die er uit zien als een functie, maar dat niet zijn. We noemen ze speciale vormen (special forms ) en ze zijn te herkennen aan bepaalde sleutelwoorden (keywords). Ze behoren tot de basissyntaxis van SCHEME en volgen de hogergenoemde evaluatieregels niet noodzakelijk. Daarom worden ze ook vaak syntax genoemd in plaats van special form.
De speciale vorm (QUOTE expressie) verhindert de evaluatie van de expressie die als argument aan QUOTE wordt gegeven. Een synoniem van (quote expressie) is ' expressie. Door al of niet gebruik te maken van de quote bepalen we of een lijst geïnterpreteerd wordt als data of als functie, en of een symbool geïnterpreteerd wordt als naam of als variabele-binding.
> (+ 1 2 3) 6 > (quote (+ 1 2 3)) (+ 1 2 3) > '(+ 1 2 3) (+ 1 2 3)De programmeur kan zelf waarden toekennen aan symbolen. Dat gebeurt met de special form (DEFINE symbool expressie). Merk op dat de evaluatie van DEFINE afwijkt van de hogergenoemde evaluatieregel: het eerste argument wordt niet geëvalueerd.
> (define appel 243)
243
> appel
243
> 'appel
appel
> 'jan
jan
> jan
Error: Undefined variable "jan"
> (define lijst '(1 2 3 4))
(1 2 3 4)
> lijst
(1 2 3 4)
> (define lijst (+ 1 2 3))
6
> lijst
6
> (define zin '(jan eet een appel)) (JAN EET EEN APPEL) > (define onderwerp (car zin)) JAN > (define predikaat (cdr zin)) (EET EEN APPEL) > (define werkwoord (car predikaat)) EET > (define object (cdr predikaat)) (EEN APPEL) > onderwerp JAN > werkwoord EET > object (EEN APPEL) > (car onderwerp) >>Error: Wrong type of arguments. > (cdr predikaat onderwerp) >>Error: Wrong number of arguments. > (car '()) >>Error: Wrong type of argument. > (cdr '()) >>Error: Wrong type of argument.Met CAR (uitgesproken "car" op z'n Engels) en CDR (uitgesproken "koeder") kunnen we tot om het even welke diepte doordringen in een lijst en er elementen of sublijsten uithalen. De resulterende combinatie van functies kan soms complex zijn. SCHEME heeft een uitgebreide verzameling functies die gebruikelijke combinaties van de functies CAR en CDR samenvatten: CAAR (de car van de car), CADR (de car van de cdr, het tweede element), CADADR (de car van de cdr van de car van de cdr). Elke combinatie van twee, drie of vier a's en d's tussen de c en de r is toegelaten.
> (define lidwoord (car (cdr (cdr zin)))) EEN > (define lidwoord (caddr zin)) EENWe willen ook graag lijsten in elkaar zetten. Dat kan met de functies (CONS expressie lijst), (LIST expressie*), en (APPEND expressie*).
Bij de beschrijving van functies en de argumenten die ze toelaten houden we ons aan de volgende afspraken: expressie betekent dat een argument om het even welk Scheme datatype kan zijn. Wanneer alleen een meer specifiek datatype toegelaten is als argument, gebruiken we de naam ervan, bijv. lijst. Wanneer 1 of meer expressies of datatypes kunnen voorkomen gebruiken we het plusteken (+), wanneer er nul of meer kunnen voorkomen gebruiken we de Kleene Star (*). Optionele (niet noodzakelijke) argumenten worden aangeduid met vierkantehaken.
> (cons 1 '(2 3 4)) (1 2 3 4) > (cons 'nooit object) (NOOIT EEN APPEL) > (cons 'onze (cons onderwerp nil)) (ONZE JAN) > (list onderwerp werkwoord object) (JAN EET (EEN APPEL)) > (append (list onderwerp) predikaat) (JAN EET EEN APPEL) > (append zin '(in de kerk)) (JAN EET EEN APPEL IN DE KERK) > (list 'np object) (NP (EEN APPEL)) > (list 'vp (list 'v werkwoord)(list 'np object)) (VP (V EET) (NP (EEN APPEL))) > (list 's (list 'np onderwerp) (list 'vp (list 'v werkwoord)(list 'np object))) (S (NP JAN) (VP (V EET) (NP (EEN APPEL))))
(*) 1 > (* 1 2.0) 2.0 > (+ 3 3.0 3/3) 7.0 > (- 2) -2 > (- 78 44) 34 > (/ 3) 0.3333 > (/ 25 5.0) 5.0 > (/ 2/3 3/4) 0.8888 > (max 2 3.0 15/2) 7.5 > (min 2 3.0 15/2) 2.0
1. Gegeven: (define x '(1 (2 3) (4) (5 (6) 7) 8))
Geef de SCHEME expressie die uit de lijst gebonden aan symbool x de volgende expressies haalt.
Gebruik alleen CAR, CDR, en C....Ra. 3
b. 5
c. vijfde element
d. 7
e. voorlaatste element2. Gegeven de lijst (1 (2 (3 4) 5))
a. Construeer deze lijst, alleen gebruik makend van cons, getallen en '()
b. Construeer deze lijst, alleen gebruik makend van list en getallen3. Maak een expressie die 1 achteraan de lijst (4 3 2) toevoegt.
4. Maak een expressie die het gemiddelde van een reeks getallen (1 2 3 4 5) oplevert.
> (= 1 1) #t > (equal? '(1 2 3) '(1 2 3)) #t > (equal? '(cons 1 (cons (list 2 5) (cons 3 ()))) '(1 (2 5) 3)) #f > (equal? (cons 1 (cons (list 2 5) (cons 3 ()))) '(1 (2 5) 3)) #tGebruik steeds = wanneer zekerheid bestaat dat de te vergelijken objecten getallen zijn.
> (member 'appel '(ik eet een appel met mosterd)) (APPEL MET MOSTERD) > (member 'peer '(ik eet een appel met mosterd)) #fOm te beslissen of een Lisp object gelijk is aan iets wat in de lijst zit moet natuurlijk gebruik worden gemaakt van een gelijkheidspredikaat. Het gelijkheidspredikaat dat MEMBER impliciet gebruikt is is EQUAL?.
> (member '(appel) '((peer)(appel)(pruim))) ((appel) (pruim))
(SYMBOL? expressie); (NUMBER? expressie); (LIST? expressie); (BOOLEAN? expressie). Er zijn er ook die testen of een argument een specifieke waarde heeft: (NULL? expressie) (lege lijst?), (ZERO? expressie) (nul?), (> getal getal), (< getal getal).
> (not 'aap) #f > (not (zero? 1)) #t > (and (= 5 5) 'piet) PIET > (and (= 0 0.0) 'tafel (member 'appel '(peer pruim))) #f > (and (= 0 0.0) 'tafel (member 'appel '(peer appel pruim))) (APPEL PRUIM) > (or #f (zero? 3) 'piet) PIET > (or #f (zero? 3)(member 'appel '(peer pruim))) #f > (or) #f > (and) #t
> (define x 0) 0 > (if (not (zero? x)) 'niet-nul 'nul) NUL
(caddr lijst)te moeten schrijven. De volgende functiedefinitie zorgt hiervoor.
> (define third (lambda (lijst) (caddr lijst))) THIRDIn dit geval kunnen we natuurlijk ook gewoon (define third caddr) schrijven, aangezien CADDR een voorgedefinieerde functie is.
Een Lambda expressie (LAMBDA (symbool*) expressie+) is een special form die evalueert tot een procedure, en bestaat uit een lijst met als eerste element het keyword LAMBDA, gevolgd door een lijst met de naam of namen van de parameter(s) van de functie (de parameter lijst). Parameters zijn variabelen (namen voor plaatsen in het geheugen waar een waarde opgeslagen kan worden). In het voorbeeld heeft de parameterlijst slechts één element: lijst. De overige argumenten van de lambda-expressie noemt men het lichaam (de body) van de functiedefinitie, deze bestaat uit een of meer Scheme expressies die achtereenvolgens worden geëvalueerd met de parameters gebonden aan de argumenten van de functieaanroep.
Net zoals met DEFINE symbolen kunnen worden gebonden aan een waarde, kan deze special form ook gebruikt worden om een procedure, gedefinieerd in een lambda expressie, te binden aan een symbool. Het eerste argument van DEFINE is een symbool, de naam van de procedure (in ons voorbeeld THIRD), en het tweede argument is de lambda expressie die de definitie bevat. De waarde die het Scheme systeem retourneert na een aanroep van DEFINE is het eerste argument (de functienaam). Belangrijker is natuurlijk het neveneffect: vanaf nu kent LISP de nieuwe functie en kunnen we ze gaan toepassen op argumenten.
> (third '(1 2 3 4)) 3 > (third (cons 'appels '(list 'peren 'pruimen 'bananen))) PRUIMENBij deze laatste functie-aanroep gebeurt het volgende: het resultaat van de evaluatie van het argument van third (de lijst (appels peren pruimen bananen)) wordt gebonden aan de parameter lijst. Met deze binding wordt (caddr lijst))) geëvalueerd, wat PRUIMEN oplevert. Aangezien de body van de definitie alleen uit die expressie bestaat is het resultaat ervan meteen ook het resultaat van de hele functieaanroep. Tenslotte wordt de binding van lijst ongedaan gemaakt. Als er in een functiedefinitie meer dan één parameter is, moet met elk van deze parameters een argument corresponderen wanneer de functie uitgevoerd wordt, zoniet volgt er een foutmelding. Het eerste argument wordt daarbij gebonden aan de eerste parameter, het tweede aan de tweede enz. Het is ook mogelijk dat er geen parameter is, zoals in de volgende, nogal stompzinnige functiedefinitie. Dat was ook het geval bij de functies S, NP, etc. in de inleiding.
> (define foo (lambda () 'hello_world!)) FOO > (foo) HELLO_WORLD!Naast de syntaxis (DEFINE symbool expressie) voor variabelebinding zorgt (DEFINE symbool lambda-expressie) dus voor de associatie van een procedure met een naam.
Deze syntaxis wijkt af van die van functiedefinitie zoals gebruikt in de voorbeelden van de inleiding. Er bestaat inderdaad een alternatieve syntaxis van functiedefinitie die voor sommigen duidelijker is. We zullen beide syntaxen gebruiken:
(DEFINE (functienaam parameternaam*) expressie+)
De volgende twee functiedefinities zijn dus volledig equivalent.
(define (foo lis1 lis2) (length (append lis1 lis2))) (define foo (lambda (lis1 lis2) (length (append lis1 lis2))))
(DISPLAY expressie). Schrijft een representatie van expressie naar de standaard output (Lisp interactiesysteem; listener).
(NEWLINE). Stuurt een end-of-line naar standaard output (nieuwe regel).
1. Definieer een procedure OPPERVLAKTE die de oppervlakte van een functie geeft, gegeven de straal.
> (oppervlakte 12)
452.3893421762. Definieer een procedure KRUISING die twee pare kruist:
> (kruising '(a b) '(1 2))
((a 2) (1 b))3. Definieer een predikaat KLINKER? dat #t geeft als het argument een klinker is.
4. Definieer een procedure VOEGTOE die een element toevoegt aan een lijst wanneer dat element nog niet voorkomt in de lijst.
> (voegtoe 'a '(b c d))
(a b c d)
> (voegtoe 'c '(b c d))
(b c d)