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); Java: public final int = 34; 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 24) Datalogi 1 Hösten 2012 1 / 29
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 24) Datalogi 1 Hösten 2012 2 / 29
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; DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 3 / 29
Variabeldeklarationer En variabel är ett lagringsutrymme. Man måste skilja på statiska och dynamiska variabler. DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 4 / 29
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. I Python är deklarationerna implicita, variablerna oftast statiska och namnen som refererar till dem försvinner då deras omgivning avvecklas. x = 3.5 ok = x < 2.0 x ok 3.5 False DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 5 / 29
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. class xref: x = None def init (self, xval): self.x = xval >>> x = xref(3.5) >>> x.x 3.5 >>> DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 6 / 29
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å. I Python kan man inte utplåna objekt. x = None tar bara bort referensen till objektet som städas bort automatiskt om det inte finns flera referenser. del(x) gör precis samma sak, men utplånar också variabeln x DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 7 / 29
Samtidiga deklarationer I Scheme kan skapandet av variablerna ske i vilken ordning som helst, och alltså får deklarationerna inte vara beroende av varandra : (define (f x y) (let ((a (+ 1 (* x y))) (b (* x y))) (+ (* x a a) (* y b) (* a b)))) I Python kan man få samma effekt med a, b = 1 + x * y, x * y men där är ordningen bestämd. DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 8 / 29
Sekvensiella deklarationer kan vara beroende av varandra. Det är vanligast med sekvensiella deklarationer. (define (f x y) (define a (+ 1 (* x y))) (define b (- a 1)) (+ (* x a a) (* y b) (* a b))) (define (f x y) (let* ((a (+ 1 (* x y))) (b (- a 1))) (+ (* x a a) (* y b) (* a b)))) DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 9 / 29
Rekursiva deklarationer är deklarationer som görs i termer av sig själva. I Python och Scheme kan funktions-(procedur-)deklarationer vara rekursiva. I ML kan även typdefinitioner vara det. DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 10 / 29
Ömsesidig rekursion utgör ett problem i många språk men inte i Python eller Scheme eftersom det inte finns krav på att namn skall existera förrän vid exekvering. (define (f n) (define (g n) (if (= n 0) (if (= n 0) 0 1 (g (- n 1)))) (f (- n 1)))) def f(n): def g(n): if n == 0: if n == 0: return 0 return 1 else: else: return g(n-1) return f(n-1) DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 11 / 29
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 och Python, det finns en skräpsamlare som kastar bort allt som inte längre refereras till, namn, variabler & omgivningar. DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 12 / 29
I Scheme är ett block en procedurkropp. I Python är klasser och funktioner block. 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 24) Datalogi 1 Hösten 2012 13 / 29
Abstraktion Inom programmeringstekniken används två former av abstraktion dataabstraktion och programabstraktion. Dataabstraktion handlar om aggregat för att gruppera samhörande data. Programabstraktion sönderfaller i två delar procedur- resp funktions-abstraktion. funktionsabstraktion procedurabstraktion DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 14 / 29
Abstraktion... En procedurabstraktion har som uppgift att uppdatera för proceduren globala storheter/strukturer. En funktionsabstraktion utför en beräkning och återsänder ett (eventuellt komplext) värde. Alla funktionsabstraktioner återsänder ett värde till anropspunkten. Detta kan ske genom att, som i funktionella språk, det sist beräknade värdet återsänds eller, som i vissa imperativa språk, man dels talar om att beräkningen inte kan fortsätta, dels anger ett värde att återsända eller, som i andra imperativa språk, funktionen har en pseudovariabel (funktionens namn) vilken tilldelas ett värde. DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 15 / 29
Abstraktion... Ex: en funktion som ger minsta värdet av tre: Python: def min(a, b, c) tmpmin = a if b < tmpmin: tmpmin = b if c < tmpmin: tmpmin = c return tmpmin DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 16 / 29
Abstraktion... Scheme: (define (min a b c) (if (and (< a b) (< a c)) a (if (< b c) b c))) DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 17 / 29
Abstraktion... C: min (a, b, c) int a, b, c; { if (a < b && a < c) return a; if (b < c) return b; return c; } DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 18 / 29
Abstraktion... Funktioner i Scheme kan återsända sammansatta värden: (define (minmax x) (define (inner x min max) (cond ((null? x) (list min max)) ((< (car x) min) (inner (cdr x) (car x) max)) ((> (car x) max) (inner (cdr x) min (car x))) (else (inner (cdr x) min max)))) (inner (cdr x) (car x) (car x))) DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 19 / 29
Abstraktion... Och i Python också def minmax(v); min = max = v[0] for i in range(1, len(v)): if v[i] < min: min = v[i] elif v[i] > max: max = v[i] DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 20 / 29
Abstraktion... Procedurabstraktioner är abstraktioner som endast arbetar via bieffekter, t.ex. skiver till fil, uppdaterar globala variabler... I funktionella språk åstadkoms procedurabstraktioner genom att vissa funktioner får returnera ett resultat som man inte tar hand om eftersom resultatet är irrelevant för funktionen och ingen är intresserad av det. Ex: Scheme: (define (errormsg msg) (display msg) (newline)) DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 21 / 29
Abstraktion... En abstraktion skall vara väldefinierad Abstraktionen skall utföra endast en (ev komplex) arbetsuppgift, och utföra denna enda uppgift väl (= korrekt och effektivt). modulärt begriplig Abstraktionen skall ha en betydelse även ryckt ur sitt sammanhan, dvs inte arbeta med globala storheter (skicka allt med parametrarna). robust Abstraktionen upptäcker när indata ligger utanför definitionsområdet och hanterar felsituationer på ett relevant sätt. väldokumenterad Abstraktionen skall vara försedd med pre- och postvillkor och om delar av algoritmen är svårbegriplig skall denna del vara kommenterad DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 22 / 29
Abstraktion... I vissa språk kan vi göra högre ordningens abstraktioner: Funktioner och procedurer som tar funktioner och procedurer som parametrar och genererar funktioner def gen_do_to_each(to_do): def do_to_each(a_list): tmp = list() for i in a_list: tmp.append(to_do(i)) return tmp refturn do_to_each (define (gen-do-to-each f) (lambda (a-list) (if (null? a-list) () (cons (f (car alist)) ((gen-do-to-each (cdr alist) f)))) DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 23 / 29
Abstraktion... Funktioner som ger funktioner som resultat (define (power n) (lambda (x) (expt x n))) ML med: fun upcasechar (s: string) = if ord s >= ord "a" andalso ord s <= ord "z" then chr (ord s + ord "A" - ord "a") else s; kan upcase skrivas som: val upcase = implode o map (upcasechar) o explode; DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 24 / 29
Parametrar För att en abstraktion skall vara modulärt begriplig måste alla strukturer och storheter som används av abstraktionen sändas som parametrar. Det är då viktigt att parametrarna sänds med rätt mekanism. Olika språk ger då olika möjligheter, beroende på vad som kan sändas och vilka mekanismer man kan använda. Traditionellt skiljer man på tre olika mekanismer DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 25 / 29
Värdeöverföring Grundläggande mekanism i de flesta programspråken. Den aktuella parametern beraäknas och det erhållna värdet substitueras in för varje förekomst av den formella parametern i algoritmen. FUNCTION f(x, y: Integer): Integer; BEGIN x := x + y; f := 2 * x END; DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 26 / 29
Referensöverföring I Pascal sker referensöverföring om parametern föregås av VAR eller om parametern är en funktion eller procedur. Det innebär att den formella parameter är en referens till den aktuella parametern. En referens kan ses som en adress till den aktuella variabeln, proceduren eller funktionen. PROCEDURE minmax(v: vector; VAR min, max: Integer); VAR i: index; BEGIN min := v[1]; max := v[1]; FOR i := 2 TO maxindex DO IF v[i] < min THEN min := v[i] ELSE IF v[i] > max THEN max := v[i]; END; DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 27 / 29
Namnöverföring Den aktuella parametern evalueras inte förrän den förekommer i algoritmen, d v s att den aktuella parametern, utan evaluering, substitueras för varje förekomst av den formella parametern. Ex (Simula): REAL PROCEDURE sum(x, i, m, n); NAME x, i; REAL x; INTEGER i, m, n; BEGIN REAL summa; summa := 0; FOR i := m STEP 1 UNTIL n DO summa := summa + x; sum := summa END; anropet OutFix(sum(a(i) * b(i), i, 1, 100), 10, 5); ger a(1) * b(1) + a(2) * b(2) +... + a(100) * b(100) Detta brukar även kallas lat evaluering, d v s inga parametrar evalueras förrän de behövs för beräkningen. Exemplet är också en bra illustration av att bieffekter ger obegripliga resultat ibland. DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 28 / 29
Parametrar... Intimt förknippat med de olika parameteröverföringsmekanismerna är beräkningsordning vid utförande av abstraktioners algoritmer. Med applikativ ordning beräknas alltid parametrars värden innan anropet till abstraktionen utförs. Med lat evaluering eller normal ordning erhålls en annan beräkningsordning, men där alla parametrar behandlas lika. Det går inte att evaluera procedur-/funktions-parametrar förrän då de förekommer i algoritmen vilka argument skulle man använda? Alltså låter man alla parametrar hanteras lika med sen eller lat evalueringsordning. Två språk av de jag känner till har lat evaluering Miranda (liknar ML) och Haskell, Två ger valmöjlighet Simula och Algol60 De flesta har applikativ ordning, men gör undantag för abstraktioner. DA2001 (Föreläsning 24) Datalogi 1 Hösten 2012 29 / 29