Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson

Relevanta dokument
Dagens föreläsning. Modeller för programmeringsspråk. - Olika modeller programspråk Interpretator - kompilator. - Syntax - semantik.

Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson

Tentamen i. TDDC67 Funktionell programmering och Lisp

Imperativ programmering. Imperativ programmering konstruktioner i Lisp. Datastrukturer (kap ) arraystruktur poststruktur

Dagens föreläsning Programmering i Lisp. - Bindning av variabler (avs 14.6) fria variabler statisk/lexikalisk och dynamisk bindning

Tentamen i. TDDA 69 Data och programstrukturer

Dagens föreläsning Programmering i Lisp Fö 5

Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson 2

Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson

Uppgift 6A - Frekvenstabell

TENTAMEN I PROGRAMSPRÅK -- DVG C kl. 08:15-13:15

Dagens föreläsning. Diverse Common Lisp. Konstanter, parametrar, globala variabler

OMTENTAMEN I PROGRAMSPRÅK -- DVG C kl. 08:15-13: 15

Våra enkla funktioner eller procedurer

TDDC74 Lab 04 Muterbara strukturer, omgivningar

Två fall: q Tom sekvens: () q Sekvens av element: (a b c) ; (sum-rec '(2 4 6)) = 12. q Första elementet uppfyller vissa villkor: (2 a b c)

TDDC74 Programmering: Abstraktion och modellering Tentamen, onsdag 9 juni 2016, kl 14 18

Dagens föreläsning Programmering i Lisp Fö 7. Sammanfattning funktionell programmering Exempel på funktionella programspråk

Dagens föreläsning. - Vad skall vi kunna inför den skriftliga examinationen? - Vad skall vi ta med oss till andra kurser.

TDDC74 Programmering: Abstraktion och modellering Tentamen, lördag 29 augusti 2015, kl 8 12

BEGREPP HITTILLS FÖRELÄSNING 2 SAMMANSATTA UTTRYCK - SCHEME DATORSPRÅK

TDDC74 Programmering, abstraktion och modellering DUGGA 2

Inledning. Vad är ett datorprogram, egentligen? Olika språk. Problemlösning och algoritmer. 1DV433 Strukturerad programmering med C Mats Loock

TDP002 - Imperativ programmering

Programmering I Tobias Wrigstad fredag, 2009 augusti 28

TDDC74 Programmering: Abstraktion och modellering Tenta, kl 14 18, 11 juni 2014

allt.cl Page 1 of 17 Date: torsdag 7 december 2006

TDDC74 Programmering: Abstraktion och modellering Tentamen, lördag 27 augusti 2016, kl 8 12

Repetition C-programmering

Signalflödesmodellen. Två (gamla) exempel: Kvadratera alla jämna löv.

TDDC74 Programmering, abstraktion och modellering. Tentamen

Uppgift 4A - Definition av enkla funktioner

Rekursiva algoritmer sortering sökning mönstermatchning

n Detta för att kunna koncentrera oss på n Tal: number? n Symboler: symbol? n Strängar: string? n Tecken: char? n Boolskt: boolean?

TDDC74 PROGRAMMERING: ABSTRAKTION OCH MODELLERING VT 2017

Programmering i C++ En manual för kursen Datavetenskaplig introduktionskurs 5p

TDDC74 Programmering: Abstraktion och modellering Datortenta

TDDC74 Programmering: Abstraktion och modellering Tentamen, onsdag 19 oktober 2016, kl 14 18

F4. programmeringsteknik och Matlab

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Exempelduggan. Luffarschack. Koda spel

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Introduktion till programmering SMD180. Föreläsning 2: Variabler, uttryck och satser

TDDC74 Programmering: Abstraktion och modellering Dugga 2, , kl 14-16

Föreläsning 3: Booleans, if, switch

TDDC74 Programmering: Abstraktion och modellering Datortenta , kl 14-18

TDDC74 Programmering, abstraktion och modellering. Tentamen

Typsystem. DA2001 (Föreläsning 23) Datalogi 1 Hösten / 19

I dag: Blockstruktur, omgivningar, problemlösning

Klassdeklaration. Metoddeklaration. Parameteröverföring

Program & programmering

Introduktion C-programmering

Funktionens deklaration

Lösningsförslag. TDDC74 Programmering: Abstraktion och modellering. Dugga 3 (provkod TEN1), Tid: kl 14-16, Datum:

Command line argumenter. Objektorienterad Programmering (TDDC77) Vad blir resultatet? Nu då? Ahmed Rezine. Hösttermin 2016

LABORATION 1. Inledande Lisp - rekursion

Objektorienterad Programmering (TDDC77)

Typsystem. Typsystem... Typsystem... Typsystem... 2 *

TDIU01 - Programmering i C++, grundkurs

Deklarativ programmering

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

Språket Scheme. DAT 060: Introduktion till (funktions)programmering. DrScheme. uttryck. Jacek Malec m. fl. evaluering av uttryck.

Repetition i Python 3. Exemplen fac. Exemplen fac motivering. Exemplen fac i Python

TDDC74 Programmering, abstraktion och modellering. Tentamen

Introduktion till programmering och Python Grundkurs i programmering med Python

Deklarationer/definitioner/specifikationer

FÖRELÄSNING 2, TDDC74, VT2018 BEGREPP PROBLEMLÖSNING MED HJÄLP AV FALLANALYS PROBLEMLÖSNING MED HJÄLP AV REKURSION

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson

FÖRELÄSNING 1 PERSONAL TDDC74 PROGRAMMERING: ABSTRAKTION OCH MODELLERING VT 2017 SYFTE EXAMINATION ORGANISATION

TDDC74 Programmering: Abstraktion och modellering Datortenta , kl 14-18

(Man brukar säga att) Java är... Denna föreläsning. Kompilering av Java. Historik: Java. enkelt. baserat på C/C++ Allmänt om Java

TDDC74 Programmering: Abstraktion och modellering Dugga 2, , kl 17-19

Objektorienterad programmering i Java

Föreläsning 2 Programmeringsteknik och C DD1316. Mikael Djurfeldt

TDDC77 Objektorienterad Programmering

TDDC74 Programmering, abstraktion och modellering. Tentamen

Procedurer och villkor. Rekursiva procedurer. Exempel: n-fakultet

Procedurer och villkor

Deklarativ programmering

Funktioner. Linda Mannila

TDDC74 Programmering, abstraktion och modellering DUGGA 1

Lambdas. (och fler design patterns) Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2017

DVG C01 TENTAMEN I PROGRAMSPRÅK PROGRAMMING LANGUAGES EXAMINATION :15-13: 15

OOP Objekt-orienterad programmering

Metoder (funktioner) Murach s: kap Winstrand Development

GU / Chalmers Campus Lindholmen Tentamen Programutveckling LEU 482 / TIG167

Översikt. Varför lära sig detta? Motivering Syntax och semantik Imperativa språkets byggstenar och Python. PL-boken Kap 1 (repetition):

TDDC74 Programmering: Abstraktion och modellering Datordugga 2 - exempel

Grundläggande datalogi - Övning 1

MATLAB. Python. Det finns flera andra program som liknar MATLAB. Sage, Octave, Maple och...

Outline. I Vi kan lätt göra samma sak för fyra variabler... I Hur gör vi för 400 inlästa värden? I Ofta behöver man flera likadana variabler

Att skriva till och läsa från terminalfönstret

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Programmering med Java. Grunderna. Programspråket Java. Programmering med Java. Källkodsexempel. Java API-exempel In- och utmatning.

Föreläsning 3. Stack

Symbolisk data. quote. (define a 1) (define b 2) (jacek johan david) (list a b)

Föreläsning 2 Programmeringsteknik och Matlab DD1312. Programspråk. Utskrift på skärmen

Föreläsning 6: Introduktion av listor

Föreläsning 2. Operativsystem och programmering

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Muddy. Funktioner / metoder. Punktnotation. Evalueringsordning

Transkript:

1 2 Dagens föreläsning En konstruktion i Common Lisp som möjliggör att man kan skapa ny Lisp-kod, som i sin tur beräknas. - makrobegreppet - makrofunktioner - special form - makrodefintion - backquote - rekursivt definierade makrofunktioner - problem med namnkollision - vad kan definieras som makros: - ej beräkning av argumenten till en funktion, ex trace, defun - utvigning av språket - egna styrstrukturer, dvs argumenten beräknas speciellt, ex while, for - effektivisering, abstrakta datatyper Jämför föregående föreläsning: Funktion - interpretator/beräknare Makro - kompilator/översättare Makro-begreppet Begreppet förekommer i samband med progamspråk eller programmering, men kan ha en lite olika betydelse i olika sammanhang. I samband med programspråk innebär detta ofta en förbearbetning av programtext. En preprocessor. Till exempel att textsträngar byts ut mot andra. C med #define där konstant text kan ersättas: #define PROGRAM int main( void ) #define BEGIN { #define END ;} PROGRAM int main( void ) BEGIN { printf( "Hallo!\n" ) printf( "Hallo!\n" ) END ;} Man kan göra in-line av en funktion: #define sgn(a) (a< 0? -1 : 1) x = pow ( fabs ( x ), 2.0 ) * sgn ( x ); x = pow ( fabs ( x ), 2.0 ) * (x< 0? -1 : 1); Man kan styra med villkorliga makro med #if. 3 4 Makrofunktioner i Lisp Olika slags funktioner i Lisp Vi kan generalisera denna förprocessering till att utföras när programmert bearbetas, direkt under interpreteringen eller vid kompilering. Eftersom Lisp-program är representerade i språkets egna datstrukturer kan vi göra denna bearbetning på den strukturella - representations -nivån i stället för på text-nivån. Vi kan nu definiera makrofunktioner med hela Lispspråkets kraft. Vi behöver inget speciellt makrospråk. Med denna makro-facilitet är det enkelt att bygga ut språket med nya konstruktioner. Lisp-språket självt utnyttjar denna möjlighet att skapa nya kontrsuktioenr mycket omfattande. Normala funktioner Beräknar sina argument enligt call-by-value. Beräkna argumenten först, applicera sedan funktionen. Hanteras av Lisp s apply-funktion. Special form Funktioner som är hårdkodade direkt i Lisp-interpretatorn. Nya kan ej definieras! if, progn, quote, setq, return,... Makrofunktioner Funktioner i Common Lisp som vanligen beräknar sina argument på eget sätt, som kan överföras till normala funktioner eller special form. Nya kan definieras! cond, or, and, setf, dotimes

5 6 I Lisp-evaluatorn (minlisp från kap 21 och föregående föreläsning) kan vi observera följande: (defun mini-eval (form env) ; uttryck x symboltabell -> uttryck (cond ((constant? form) (evaluate-constant form)) ((variable? form) (lookup-value form env)) ((conditional? form) (eval-conditional (clauses form) env)) (t (mini-apply (function-part form) (evalargs (args-part form) env) env)))) special form Här bearbetas vanliga call-by-value - funktioner beräkna alla argumenten (defun mini-apply (fn args env) ; funktion x argumentlista x symboltabell -> uttryck (cond ((primitive-function? fn) (primitive-apply fn args)) ((function-symbol? fn) (mini-apply (lookup-definition fn) args env)) ((lambda? fn) (mini-eval (body fn) (extend-env (bind (formal-params fn) args) env))) (t (error "u.d.f - undefined function ~s" fn)))) Definition av egna makrofunktioner. (defmacro makronamn parameterlista makrokropp) Obs. Parametrarna binds till de oevaluerade aktuella parametrarna (ej som för vanliga funktioner, där argumenten först beräknas) Makroexpansion - tvåstegs process översättning och beräkning (makrofn arg1 arg2... argn) => makrofunktionen för makrofn appliceras på argumenten och översättning => ger som resultat ett nytt Lisp-uttryck => som i sin tur ges för beräkning Jämför från tidigare föreläsning: funktion - interpretator -> ger ett värde makro - kompilator -> ger programkod 7 8 När sker makroexpansion? vid interpretering direkt efter varandra: översättning beräkning vid kompilering två olika tillfällen: översättning vid kompilering beräkning vid exekveringstillfället (av den kompilerade koden) Detta betyder att man vid definition av en makro ej får förutsätta kännedom om variabler, funktioner mm som ej är tillgängliga vid makroexpansionstillfället. Därför kan man vanligen ej använda eval. Med interpretatorfunktionen eval kan vi beräkna ett Lisp-uttryck vi skapat. (eval (list first (list quote (a b c)))) -> (eval (first (quote (a b c)))) -> (first (quote (a b c))) => a Interpretatorfunktionen apply är en variant av funcall. (apply # (lambda (op args) (cons op args)) (+ (1 2 3)))) => (+ 1 2 3) lista med färdigberäknade argument Makroexpansion kan då i dessa interpretatorfunktioner beskrivas enligt följande: Beräkning av makrouttrycket makuttr = (makrofn arg1... argn): görs genom att Lisp gör följande: (eval (apply makrofunktionen för (first makroutr) (rest makuttr)))

9 10 Om vi på något sätt kan känna igen makrofunktioner, så kan vi implementera makroutveckling i minilisp enligt följande: (defun mini-eval (form env) ; uttryck x symboltabell -> uttryck (cond ((constant? form) (evaluate-constant form)) ((variable? form) (lookup-value form env)) ((conditional? form) (eval-conditional (clauses form) env)) ((macro-function? form) (mini-eval (mini-apply (lookup-macro-def (function-part form)) (args-part form) env) env)) ingen evaluering av argument makroutvecklingen jämför (t (mini-apply (function-part form) (evalargs (args-part form) env) env)))) Funktionen evalargs evaluerar argumenten i en argumentlista. Exempel: Vi önskar använda två-vägs cond-uttryck, som vi kallar cond-2. Språket tillhandahåller endast ett if-uttryck. (defun f (l) (cond-2 ((endp l) nil) (t (first l))) ) Definiera en makrofunktion för cond-2: - 2 fall (defmacro cond-2 (cl1 cl2) (list if (first cl1) (second cl1) (second cl2))) En test av funktionen f med ett argument: (f (a b c)) -> (cond-2 ((endp l)...)...) -> l binds till (a b c) makroutveckling av cond-2: -> (eval (apply # (lambda (cl1 cl2) (list if (first cl1) (second cl1) (second cl2))) (((endp l) nil) (t (first l)))) cl1 binds till ((endp l) nil) cl2 binds till (t (first l)) -> (eval (if (endp l) nil (first l))) => a kod blir argument 11 12 Backquote som quote, men uttryck inne i det backquote ade uttrycket kan beräknas. Mycket lämplig att använda i samband med att man definierar makrofunktioner. Uttryck efter kommatecken beräknas! (a,(+ 13 5) (x,(list a b))) => (a 18 (x (a b))) Jämför med quote: (a (+ 13 5) (x (list a b))) => (a (+ 13 5) (x (list a b))) (let ((l (a b c))) (a (,(second l) c d),(rest l)) => (a (b c d) (b c)) Backquote (a,(+ 13 5) (x,(cons a b))) är samma som (list a (+ 13 5) (list x (cons a b))) (backquote) är ett sk readmacro som utförs vid inläsningstillfället (samma som vanliga quote) Dessutom finns,@ som slice ar in en lista (let ((lista (x y))) (a,@lista b)) => (a x y b)

13 14 Makrodefinitionen av cond-2 (defmacro cond-2 (cl1 cl2) (list if (first cl1) (second cl1) (second cl2))) kan därför ersättas med: (defmacro cond-2 (cl1 cl2) (if,(first cl1),(second cl1),(second cl2))) Lisp använder makroutveckling Med funktionen macroexpand-1 kan man se resultatet av makroutvecklingen. Även cntrl-c m och menyn under ACL -> debug. (macroexpand-1 (cond (a b) (t c))) => (IF A (PROGN B) (COND (T C))) (macroexpand-1 (and a b c)) => (COND ((NOT A) NIL) ((NOT B) NIL) (T C)) (macroexpand-1 *) (1) => (IF (NOT A) (PROGN NIL) (COND ((NOT B) NIL) (T C))) (macroexpand-1 (or a b c)) => (COND (A) (B) (T C)) (macroexpand-1 *) (LET ((#:G6373 A)) (IF #:G6373 #:G6373 (COND (B) (T C)))) (1) I Common Lisp betyder på toppnivån * (som variabel) senaste utmatning. 15 16 Användning av makrofunktioner Oevaluerade argument Effektivisering Kompilering av primitiver, genom att ersätta anrop med definitionen och substituera in aktuella parametrar. (defun skapa-klockslag (min tim) (cons min tim)) kan då ersättas med makrofunktionen: (defmacro skapa-klockslag (min tim) (cons,min,tim)) Koden: (... (skapa-klockslag m (start-tim s))...) makroutvecklas till (... (cons m (start-tim s))...) som sedan kan kompileras till t. ex. maskinkod I många funktioner quote ar man ej argumenten, ex (trace remove) (defun f (x y) (list y x)) (setq kalle (+ 10 20)) Vi har definierat en boka-funktion där vi skriver: (boka 1 jan (10 30) (12 30) möte ) Antag vi vill ha en boka utan att behöva quote a argumenten: (boka 1 jan (10 30) (12 30) möte ) (defmacro boka (d m start slut akt) (boka-int,d,m,start,slut,akt)) där boka-int är den utsprungliga boka-funktionen

17 18 Annan evalueringsordning av argument (dvs ej call-by-value) Skriv en funktion om som fungerar som if. Fungerar (defun om (p s1 s2) (if p s1 s2)) Javisst! (om (> 10 5) (+ 10 2) (- 10 2)) => 12 Men? (defun fak (n) (om (= n 0) 1 (* n (fak (1- n))) )) (fak 3)? (fak 2) -> (om nil 1 (* 2 (fak 1))) -> (om nil 1 (* 2 (om nil 1 (* 1 (fak 0))))) -> (om nil 1 (* 2 (om nil 1 (* 1 (om t 1 (* 0 (fak -1)))) ))) -> (om nil 1 (* 2 (om nil 1 (* 1 (om t 1 (* 0 (om nil (* -1 (fak -2))) )))))) -> i oändlig repetition! Definiera om som en makro: (defmacro om (p s1 s2) (if,p,s1,s2)) 19 20 Annat exempel: Öka en global variabel med ett värde. (setq nr 10) (incr nr (+ 2 3)) - öka nr med 5, dvs -> (setq nr (+ nr (+ 2 3))) nr => 15 (defmacro incr (glob-var val-expr) (setq,glob-var (+,glob-var,val-expr)))) Detta problem kan lösas i vissa andra språk med en möjlighet att ha utparametrar och parameteröverföringsmodellen call-by-reference. I Ada kommer ni träffa på denna möjligheten. Finns ej i Java. Rekursivt definierat makro Givet en binär operator binplus. Skapa en operator plus som tar ett godtyckligt antal argument. Använd makro och gör en stegvis översättning av uttrycket till binplus. (plus) -> 0 (plus x) -> x (plus x y z 8) -> (binplus x (plus y z 8)) (defmacro plus (&rest args) (cond ((endp args) 0) ((endp (rest args)) (first args)) (t (binplus,(first args) (plus,@(rest args))) )))

21 22 Tillägg av nya styrstrukturer Exempelvis iterativa strukturer från Ada (while, for etc) (let ((i 10)) (while (> i 0) (print i) (setq i (- i 1)))) skriver ut 10, 9, 8, tom 1 Hitta motsvarande iterativa konstruktion och använd den som mall. (let ((I 10)) (loop (unless (> i 0) (return nil)) (print i) (setq i (- i 1))))) Makrodefinition av while (defmacro while (pred &rest exprs) (loop (unless,pred (return nil)),@exprs)) I Common Lisp Det finns en mycket omfattande loop-konstruktion, som tillåter alla tänkbara sätt att vilja beskriva en repetition. Dessa makroutvecklas. (Se t ex http://www.franz.com/support/documentation/8.2/ansicl/dictentr/loop.htm) (loop for i from 1 to 10 do (print i)) skriver ut 1, 2... 10 (macroexpand-1 (loop for i from 1 to 10 do (print i))) =>(utvecklas till lite förenklat) (block nil (let ((I 1)) (tagbody next-loop (print I) (setq I (+ i 1)) (when (> i 10) (go end-loop)) (go next-loop) end-loop))) 23 24 (defun f (max) (loop for n from 1 to max when (oddp n) collect n)) (f 10) => (1 3 5 7 9) (macroexpand-1 (loop for n from 1 to max when (oddp n) collect n)) => (utvecklas till förenklat) (block nil (let* ((n 1) Tekniken att bygga upp resultatet tas upp mer i nästa föreläsning (loop-list-head (list nil)) (loop-list-tail loop-list-head)) (tagbody next-loop (if (oddp n) (setf (cdr loop-list-tail) (setq loop-list-tail (list n)))) (setq n (+ n 1)) (when (> n max) (go end-loop)) (go next-loop) end-loop (return-from nil (cdr loop-list-head)))))) Domänspecifika programmeringsspråk (DSL) Ett specialiserat språk för en domän med sin egen syntax. På wikipedia via domänspercifika språk har vi ett scriptspråk för att beskriva ett spel. (Ett kommersilett bolag: http://en.wikipedia.org/wiki/ Zillions_of_Games#Scripting_language T ex tic-tac-toe.

25 26 Domänspecifika programmeringsspråk (DSL) Här använder man syntaxen för S-notation (dvs den vi använder i Lisp). Ett alternativ hade kunnat vara XML-taggar. (game (title "Tic-Tac-Toe") (description "...") (history "...") (strategy "...") (players X O) (turn-order X O) (board (image "images\tictactoe\tttbrd.bmp") (grid (start-rectangle 16 16 112 112) ; top-left position (dimensions ;3x3 ("top-/middle-/bottom-" (0 112)) ; rows ("left/middle/right" (112 0))) ; columns (directions (n -1 0) (e 0 1) (nw -1-1) (ne -1 1)))) (piece (name man) (help "Man: drops on any empty square") (image X "images\tictactoe\tttx.bmp" O "images\tictactoe\ttto.bmp") (drops (add-to-empty))) (board-setup (X (man off 5)) (O (man off 5))) (draw-condition (X O) stalemated) (win-condition (X O) (or (relative-config man n man n man) (relative-config man e man e man) (relative-config man ne man ne man) (relative-config man nw man nw man)))) Domänspecifika programmeringsspråk (DSL) Hur implementerar vi det domänspecifika språket? Vi kan skriva en interpretator alt. kompilator. Vi kan med hjälp av makroutveckling i Lisp kunna köra detta program (det är i S-notation) och för varje kommando skapa en makro som utvecklas till sådan kod som skapar och kör spelet. En del uttryck kan kanske direkt var körbara i Lisp (defmacro game (&rest commands)...) (defmacro title (name)...)... Vi har då genomfört en översättning av kod i det domänspecifika språket till Lisp-kod. 27 28 Problem att ta hänsyn till Ny lösning av problemet att öka global variabel med ett värde. (setq nr 10) (incr nr (+ 2 3)) skall översättas till: -> (setq nr (+ nr (+ 2 3))) felaktigt översatt till: -> (setq nr 15) (defmacro incr (glob-var val-expr) (list setq glob-var (+ (eval glob-var) (eval val-expr)))) Fungerar interpreterat men ej kompilerat! Se till att inte beräkna uttryck i onödan! Ibland blir det helt fel! Exempel: Som tidigare med incr, men öka två variabler med samma värde. (setq nr 10) (setq size 20) (incr2 nr size (+ 2 5)) - öka både nr och size med 2 nr => 17 size => 27 (defmacro incr2 (var1 var2 val-expr) (setq,var1 (+,var1,val-expr)) (setq,var2 (+,var2,val-expr)))) val-expr kommer att beräknas två gånger - tar extra tid - sidoeffekter utförs flera gånger (incr2 nr size (print 7))

29 30 Lösningen är att införa lokal variabel! (defmacro incr2 (var1 var2 val-expr) (let ((value,val-expr)) (setq,var1 (+,var1 value)) (setq,var2 (+,var2 value))))) (incr2 nr size (+ 2 (print 5))) -> (let ((value (+ 2 (print 5)))) (setq nr (+ nr value)) (setq size (+ size value)))) Utskriften av 5 kommer bara att ske en gång! Men det kan även bli variabelkollision då vi inför egen lokal variabel. Vad händer här? (setq nr 10) (setq value 100) (incr2 nr value (+ 2 5)) value =>? nr =>? (incr2 nr value (+ 2 5)) -> (let ((value (+ 2 5))) (setq nr (+ nr value)) (setq value (+ value value)))) 31 Lösning: Vi behöver ett unikt namn för den lokala variabeln. I Lisp finns en funktion gensym (generate symbol) som genererar en ny symbol. (gensym a ) => #:a11 (gensym a ) => #:a12 (defmacro incr2 (var1 var2 val-expr) (let ((local-var (gensym value ))) (let ((,local-var,val-expr)) (setq,var1 (+,var1,local-var)) (setq,var2 (+,var2,local-var)))))) (incr2 nr value (+ 2 5)) -> (let ((#:value7 (+ 2 5))) (setq nr (+ nr #:value7)) (setq value (+ value #:value7))))