Omgivningar Omgivningar är viktiga eftersom de avgör vilka namn som är synliga och därmed dessas innebörd och de värden som är förknippade med dem. (define (sqrroot c) (define (fixpoint guess c eps) (define (goodenough? x c eps) (< (abs (- (* x x) c)) eps)) (if (goodenough? guess c eps) guess (fixpoint (/ (+ guess (/ c guess)) 2.0) c eps))) (fixpoint 1.0 c 0.000000001)) DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 1 / 20
sqrroot c fixpoint guess, c, eps goodenough? x, c, eps fixpoint 1.0 c 0.000000001 DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 2 / 20
I en omgivning A syns det som är deklarerat i A och A:s globala omgivningar, men inte det som deklarerats i lokala omgivningar inuti A Lexikalt scope innebär att det endast är den deklarerade blockstrukturen som avgör vilka namn som är tillgängliga och vad de betyder. Om man däremot har dynamiskt scope så avgörs vilka namn som är tillgängliga av anropskedjan DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 3 / 20
PROGRAM scope(output); VAR i: Integer; PROCEDURE p; BEGIN i := Succ(i) END; PROCEDURE q(procedure h); VAR i: Integer; BEGIN i := 10; h; WriteLn(i: 1); END; BEGIN q(p); END. DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 4 / 20
Ett namn som inte är deklarerat i den egna omgivningen representerar en fri variabel. En fri variabel har en mening bara i samband med den yttre omgivningen. Om variabelns värde varierar mellan evalueringar av den lokala omgivningen så kommer resultatet eventuellt att variera. Försök att skriva programmen så att de enda fria namnen är sådana som representerar konstanter samt procedurer och funktioner utan fria variabler. DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 5 / 20
Deklarationer/definitioner/specifikationer Konstantdefinitioner innebär att ett namn binds och sätts att referera till ett värde som beräknas vid kompileringen/interpreteringen och som under programmets gång inte får ändras. Pascal: CONST n = 10; pi = 3.14; space = ; Simula: INTEGER n = 10; Ada: n: constant integer := 34; a: constant array (boolean) of integer :=(true => 0, false => 1); Funktions- och procedurdefinitioner binder namn till aktuell omgivning och associerar till en programabstraktion. Dessa abstraktioner utgör i sig själva lokala omgivningar. DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 6 / 20
Typdeklarationer Vi har redan konstaterat att Pascals typspecifikationer innebär att två exakt likadant specificerade typer är distinkta. I ML används strukturekvivalens, vilket har fördelar i det att typer som definierats i flera steg eller genererats av funktionsanrop, kommer att vara ekvivalenta om de har samma struktur. Men nackdelar finns också: type vara = int * string; (* varunummer H varutyp *) type avd = int * string; (* avd.nummer H avd.namn *) går inte att skilja från varandra och avsikten borde rimligtvis vara att skilja de två olika tupeltyperna åt. DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 7 / 20
Med strukturekvivalens är de per definition samma typ. I ML finns också möjligheter att genom etiketter skilja typerna åt (= göra dem till olika typer): datatype VARA = vara of int * string; datatype AVD = avd of int * string; Men (igen) Pascal har namnekvivalens: TYPE stack = RECORD store: ARRAY [1..max] OF integer; END; storage = ARRAY [1..max] OF integer; är store och storage av olika typ. DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 8 / 20
För att få likhet i typavseende: TYPE storage = ARRAY [1..max] OF integer; stack = RECORD store: storage; END; Namnekvivalens är enklast och snabbast att kontrollera, men konceptuellt lika typer måste deklareras som samma typ. Strukturell typekvivalens är tyngre för datorn då ju typuttryck måste evalueras för att klarlägga likheten och dessutom kan man inte utan extra åtgärder skilja konceptuellt olika, strukturellt ekvivalenta typer utan extra mekanismer (som datatype i ML) DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 9 / 20
Variabeldeklarationer En variabel är ett lagringsutrymme. Man måste skilja på statiska och dynamiska variabler. DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 10 / 20
Statiska variabler Deklaration av en statisk variabel innebär att ett namn definieras, binds till aktuell omgivning och sätts att referera till ett minnesutrymme som reserveras för variabeln. Statiska variabler och namnen som refererar till dem försvinner då deras omgivning avvecklas. VAR x: Integer; ok: Boolean;... x := 3.5; ok := x < 2.0; x ok x ok...... 3.5 false DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 11 / 20
Dynamiska variabler Skapas och utplånas genom speciella kommandon, försvinner inte då motsvarande omgivning försvinner och måste därför antingen förstöras innan omgivningen avvecklas eller måste en yttre referens sättas att referera till variabeln. TYPE xref = ˆx; x = RECORD val : Integer END; VAR myx: xref; FUNCTION newx(i:integer):xref; VAR tmp: xref; BEGIN New (tmp); tmpˆ.val := i; newx := tmp; END; DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 12 / 20
I Pascal måste dynamiska variabler utplånas genom kommandot dispose(namnsomrefererartillvariabeln); Scheme har endast statiska variabler. I t ex Java, C och C++ har man möjlighet till både statisk och dynamisk referens till både variabler, konstanter, objekt och procedurer. Resultatet är att man kan hantera värden både på meta -nivå och på objektnivå. DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 13 / 20
Samtidiga deklarationer kan ske i vilken ordning som helst, och alltså får deklarationerna inte vara beroende av varandra. I Pascal finns inte möjlighet till samtidiga deklarationer, men det kan åstadkommas i Scheme (define (f x y) (let ((a (+ 1 (* x y))) (b (* 1 y))) (+ (* x a a) (* y b) (* a b)))) DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 14 / 20
Sekvensiella deklarationer kan vara beroende av varandra. Det är vanligast med sekvensiella deklarationer. I Pascal är det enda möjligheten. FUNCTION f(x, y: Integer): Integer; VAR a, b: Integer; BEGIN... END; (define (f x y) (define (a (+ 1 (* x y)))) (define (b (- 1 y))) (+ (* x a a) (* y b) (* a b))) (define (f x y) (let* ((a (+ 1 (* x y))) (b (- 1 y))) (+ (* x a a) (* y b) (* a b)))) DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 15 / 20
Rekursiva deklarationer är deklarationer som görs i termer av sig själva. I Pascal och Scheme kan procedur-(funktions-) deklarationer vara rekursiva. I ML kan även typdefinitioner vara det. FUNCTION f(n: Integer): Integer; BEGIN IF n = 0 THEN f := 1 ELSE f := n * f(n - 1) END; DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 16 / 20
Ömsesidig rekursion utgör ett problem i Pascal. För att klara av det finns ett direktiv FORWARD. FUNCTION g(n: Integer): Integer; FORWARD; FUNCTION f(n: Integer): Integer; BEGIN IF n = 0 THEN f := 1 ELSE f := g(n-1) END; FUNCTION g; BEGIN IF n = 0 THEN g := 0 ELSE g := f(n-1) END; DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 17 / 20
Ömsesidig rekursion är inte ett problem i scheme eftersom det inte finns krav på att namn skall existera förrän vid exekvering. (define (f n) (if (= n 0) 0 (g (- n 1)))) (define (g n) (if (= n 0) 1 (g (- n 1)))) DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 18 / 20
Ett namn deklareras i början av ett block och syns sedan inom det aktuella blocket så länge detta existerar. Då blocket avvecklas försvinner namnet. Detta gäller alla namn. Om namnet refererar till en statisk variabel försvinner även variabeln. Om namnet refererar till en dynamisk variabel fortsätter variabeln att existera och ta upp minne tills den explicit städas bort eller om, som i ML, det finns en skräpsamlare som kastar bort allt som inte längre refereras till, namn, variabler, omgivningar. I Pascal är ett program, en procedur eller en funktion uppbyggd med ett huvud (program/procedur/funktionshuvud) + ett block. DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 19 / 20
I Scheme är ett block en procedurkropp. I ML kan varje sats vara ett block eftersom varje sats kan innehålla deklarationer. let val x = 3 in x + 2 end; I Java kan deklarationer förekomma var som helst, även mitt i ett block. Där kan variabler deklareras och tilldelas värde i en enda operation. Vill man att det värdet inte ska kunna ändras deklareras det som final. Man har dessutom metoder för att hindra insyn. private final Window w = new Window(...) ger ett fönster som inte kan ändras och som man inte kommer åt utanför blocket. DA2001 (Föreläsning 25) Datalogi 1 Hösten 2010 20 / 20