Lagring... Variabler är dataobjekt som används för lagring av värden. Dessa värden kan uppdateras och avläsas. I imperativ programmering används variabler för att lagra tillståndet hos den värld man avbildar i sitt program. I funktionell programmering är variablerna oftast knutna till någon lokal parameterlista i en funktion. De flesta variabler existerar endast under tiden som en modul av något slag existerar. Det kan vara ett program, en funktion eller en procedur, men även filer och databaser är variabler och dessa överlever programmen som använder dem. Alla variablers lagringsutrymme utgörs av en eller flera minnesceller i antingen primär- eller sekundärminnet. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 1 / 68
Lagring... Här behandlas variabler som om: de lagras i en mängd celler, en cell är allokerad (reserverad för visst ändamål) eller inte allokerad, varje cell har ett innehåll som är definierat eller odefinierat. Att en cell har ett odefinierat värde menas att värdet kan vara vad som helst, oftast det värde som råkade finnas i cellen vid allokeringstillfället. Beroende på programspråk betraktas vissa variabler som enheter eller sammansatta, beroende på om cellerna, där variabeln lagras, måste uppdateras som en helhet eller kan uppdateras selektivt (delar kan uppdateras för sig). DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 2 / 68
Lagring... I Python betraktas primitiva värden, konstanta mängder (frozenset), str, tuple och range som enheter. I Scheme betraktas primitiva värden, par, listor, funktioner och referenser till variabler som enheter. Ex (define f (lambda (x) (lambda (y) (let ((x (+ x y))) (* x y))))) f är en variabel vars värde är funktionskroppen inklusive de tre ingående variablerna x, y och x (!). DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 3 / 68
Lagring... I ML, där med definitionen type date = {year: int, month: int, day: int}; funktionen fun updatemonth(d: date, newmonth: int) = {year = #year d, month = newmonth, day = #day d}; skapar en ny post med samma värden på year och day men nytt värde på month. Poster behandlas alltså som en enhet i ML. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 4 / 68
Lagring... Ex (ML): Man kan deklarera variabler i ML. datatype day = mon tue wed thu fri sat sun ; type weeklyappointment = day * int * int; val nextapp: weeklyappointment ref = ref (mon, 13, 20); Här är day någonting helt nytt, därför datatype, medan weeklyappointment sätts samman av redan definierade typer och nextapp är en variabel vars värde kan uppdateras som helhet, men man kommer inte åt delarna annat än för avläsning. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 5 / 68
Kontinuerliga listor Finns i Scheme men inte i Python. Den avgörande skillnaden mellan diskontinuerliga listor och kontinuerliga listor är att man direkt kan komma åt enstaka element genom indexering och att de flesta implementationer av kontinuerliga listor kräver fix längd på dem. Det finns flera sätt att låsa listornas längd och dessa ger upphov till olika termer för listorna. Om indexmängden och därmed längden på listan bestäms vid: kompileringstillfället = statisk kontinuerlig lista då variabeln skapas = dynamisk kontinuerlig lista inte alls låses = flexibel kontinuerlig lista DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 6 / 68
Kontinuerliga listor... Statisk kontinuerlig lista (Pascal): CONST minrow = 0; maxrow = 100; mincol = 2; maxcol = 25; TYPE table = ARRAY [minrow..maxrow, mincol..maxcol] OF Integer; VAR mytable: table; PROCEDURE makezerotable(var atable: table); VAR i,j: Integer; BEGIN FOR i := minrow TO maxrow DO FOR j := mincol TO maxcol DO atable[i, j] := 0; END; DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 7 / 68
Kontinuerliga listor... Dynamisk kontinuerlig lista (Simula): minrow := InInt; maxrow := InInt; mincol := InInt; maxcol := InInt; BEGIN INTEGER ARRAY table(minrow:maxrow,mincol:maxcol); PROCEDURE makezerotable(atable); INTEGER ARRAY atable; BEGIN INTEGER lowrow, highrow, lowcol, highcol, i, j; lowrow := LowerBound(aTable, 1); highrow := UpperBound(aTable, 1); lowcol := LowerBound(aTable, 2); highcol := UpperBound(aTable, 2); FOR i := lowrow STEP 1 UNTIL highrow DO FOR j := lowcol STEP 1 UNTIL highcol DO atable(i, j) := 0; END; END; DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 8 / 68
Kontinuerliga listor... Flexibla kontinuerliga listor finns t.ex. i Java. Lagring av komponenter i en kontinuerlig lista sker så att konsekutiva (på varandra direkt följande) komponenter lagras konsekutivt i minnet. Ex: basadress Adressen till komponent nr i beräknas enligt: basadress + (i startindex) komponentstorlek men detta kräver att alla komponenter tar lika stor plats. Om inte detta är fallet måste följande beräknas. i j=undre-gräns s j + basadress De flesta språk som har kontinuerliga listor understödjer endast homogena kontinuerliga listor, som är enklast, undantag är t ex Smalltalk och Java. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 9 / 68
Variablers livstid En variabel skapas genom att utrymme allokeras, används (får ett värde, som kan avläsas och ändras) och utplånas genom att det reserverade utrymmet återbördas till systemet. Statiska variabler deklareras och minne allokeras då deklarationen påträffas. Existerar så länge blocket, i vilket de deklarerades, existerar. Avallokeras tillsammans med blocket. De existerar även i eventuella subblock, men kan skymmas av lokala variabler med samma namn, varvid de, under subblockets existens, inte är åtkomliga. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 10 / 68
Variablers livstid... Ex (Scheme): (define (minmax m. n) (let ((min m) (max m)) (define (loop n) (if (null? n) (cons min max) (begin (cond ((> min (car n)) (set! min (car n))) ((< max (car n)) (set! max (car n)))) (loop (cdr n))))) (loop n))) DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 11 / 68
Persistenta objekt (långlivade/uthålliga dataobjekt) Den enklaste formen långlivade dataobjekt är vanliga filer, som kan betraktas som listor på sekundärminnet. Mer generellt: Antag att det i Pyton funnes möjlighet att utöka programmens omgivning genom att kunna deklarera programvariabler som inkluderas i omgivningen så att de deklarerade variablernas värden överlever mellan programkörningar. Det kan ske genom att Pyton syntax utökas med ett reserverat ord t ex persistent. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 12 / 68
Persistenta objekt... Ex: anumber = None sum = persistent private( Serafim ) anumber = Input( mata in ett tal: ) sum += anumber På grund av den dynamiska typrningen är det här inte riktigt bra. Det vore bättre om vi kunde få typkontroll som fungerar i både språk och på filer. Man kan komma nästan ända fram med hjälp av pickle. Men bara nästan. Man måste lägga till kod för typkontroll och kod för att hålla en fil öppen för lagring av objekten och man måste lgga till kod för att spara och läsa in. Allt detta vill man slippa. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 13 / 68
Dataobjektmanipulation (Operationer på variabler) Alla språk som tillåter tilldelning innehåller ett antal programsatser som utför manipulation av innehållet i variabler. Vi kallar denna typ av satser för kommandon. En subjektiv indelning: skip, gör ingenting tilldelning, sätter värdet på en variabel proceduranrop, abstraktion för en mängd satser sekvens, följd av satser samtidiga satser, möjlighet till ickedeterminism villkorlig sats, programflödesstyrning iterativ sats, programflödesstyrning DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 14 / 68
Dataobjektmanipulation... I moderna språk behöver man aldrig skriva ut ett skip. Ex (Pascal): IF villkor THEN ELSE; betyder IF villkor THEN skip ELSE skip; a := 3; END betyder a := 3; skip END DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 15 / 68
Tilldelning Exempel a = 3 (if villkor then x else y) := 3; (* går bra i t ex ML*) m := n := 23;! går bra i t ex Simula; m = n = 23; /* i C, Python och Java */ c += d; /* c := c + d i C */ DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 16 / 68
Proceduranrop P(ap1, ap2,...,apk ); Enbart bieffekter. Är OK utan bieffekter i Ada om man deklarerar separata in- och utparametrar: procedure p (ap1, ap2,...,apk: in Integer; apk+1, apk+2,...,apk+m: out Integer) is begin... end; eftersom man har fullständig kontroll och proceduren kan ses som en process med ett antal in- och utgångar. Obs dock att proceduren inte får ha några bieffekter! DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 17 / 68
Sekvenser och samtidiga satser Sekvens, ex: a = 3 b = 4 c = a + b Samtidiga satser, Ex (Scheme): (let ((x 3) (y 4) (z (+ x y))) (let ((y x) (x y))...)) I Python x, y, z = 3, 4, x + y #Hmm.. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 18 / 68
Villkorliga satser Används för att ändra programflödet if v then s; if v then s1 else s2; if v1 then s1 elseif v2 then s2 elseif... else sn; if v1 then s1 else if v2 then s2 else if... else sn; Pascal: case expr of L1: s1; L2: s2;... Ln: sn; otherwise s; { inte standard } end; DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 19 / 68
Villkorliga satser... Python: if v1: s1 elif v2: s2... else: sn C: switch (c) { case : case \t : case \n : blanks++; break; default : nonblanks++; break; } Men... det finns villkorliga uttryck också (lätt att förväxla) DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 20 / 68
Villkorliga uttryck (cond ((> a b) a) (else (if (> b 2) b 2))) (if a > b then x else y) := 3; (* ML *) a := 3 + (if a > b then x else y);! Simula ; DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 21 / 68
Iteration Används för att åstadkomma upprepning av programavsnitt. while v do s; repeat s until v; for i := start to stop do s; for i := stop downto start do s; for i in x do s; for i := start step 3 until stop do s; for i := 1,4,17 do s; for i := i + 1 while v do s; loop s1; if v then exit; s2; end loop; DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 22 / 68
Iteration... I funktionella språk måste upprepning åstadkommas genom rekursion I deklarativa språk (utom funktionella) finns iterationen inbyggd i språket select namn from anställd where lön > 10000; fac (0, 1). fac (N, N * X) :- N > 0, fac (N-1, X). Sidoeffekter: Kan inte alltid undvikas (innebär alltid uppdatering av variabler) print(x: 1); from pickle import dump intfile = open("integerbinfile", wb )... while n >= 0: dump(n, intfile)... Undvik all användning av ickelokala variabler! DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 23 / 68
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 23) Datalogi 1 Hösten 2012 24 / 68
Typdeklarationer Vi har redan konstaterat att namnekvivalens för typer 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 $\times$ varutyp *) type avd = int * string; (* avd.nummer $\times$ 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 23) Datalogi 1 Hösten 2012 25 / 68
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; 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 23) Datalogi 1 Hösten 2012 26 / 68
Ömsesidig rekursion Ömsesidig rekursion utgör ett problem i statiskt typade språk eftersom namn Ömsesidig rekursion är inte ett problem i scheme eller Python eftersom det inte finns krav på att namn skall existera förrän vid exekvering. def f(n): if n==0: return 0 else: return g(n-1) def g(n): if n==0: return 1 else: return f(n-1) DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 27 / 68
Block i olika språk 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 23) Datalogi 1 Hösten 2012 28 / 68
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 23) Datalogi 1 Hösten 2012 29 / 68
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 23) Datalogi 1 Hösten 2012 30 / 68
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 23) Datalogi 1 Hösten 2012 31 / 68
Abstraktion... Scheme: (define (min a b c) (if (and (< a b) (< a c)) a (if (< b c) b c))) DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 32 / 68
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 23) Datalogi 1 Hösten 2012 33 / 68
Abstraktion... Men funktioner i Scheme och Python kan återsända sammansatta värden: def minmax (x): minval = maxval = x[0] for i in range(1, len(x)): if x[i] < minval: minval = x[i] elif x[i] > maxval: maxval = x[i] return minval, maxval DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 34 / 68
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 23) Datalogi 1 Hösten 2012 35 / 68
Abstraktion... Pascal: PROCEDURE printstars(n: Integer); BEGIN FOR i := 1 TO n DO Write( * ); WriteLn; END; DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 36 / 68
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 23) Datalogi 1 Hösten 2012 37 / 68
Abstraktion... I vissa språk kan vi göra högre ordningens abstraktioner: Funktioner och procedurer som tar funktioner och procedurer som parametrar def dotoeach(alist, f): for i in range(len(alist)): alist[i] = f(alist[i]) (define (do-to-each alist f) (if (null? alist) () (cons (f (car alist)) (do-to-each (cdr alist) f)))) DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 38 / 68
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 23) Datalogi 1 Hösten 2012 39 / 68
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 i många språk 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 23) Datalogi 1 Hösten 2012 40 / 68
Värdeöverföring Grundläggande mekanism i de flesta programspråken. Den aktuella parametern evalueras och det erhållna värdet substitueras in för varje förekomst av den formella parametern i algoritmen. def f(x, y): x = x + y; return 2 * x DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 41 / 68
Referensöverföring I Python sker referensöverföring om parametern är en funktion eller någon datastruktur som kan uppdateras. 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. Antag: mm = { min : None, max : None} def minmax(l, minochmax): minochmax[ min ] = minochmax[ max ] = L[0] for i in range(1, len(l)): if L[i] < minochmax[ min ]: minochmax[ min ] = L[i] elif L[i] > minochmax[ max ]: minochmax[ max ] = L[i] DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 42 / 68
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. Ett modernare sätt är att utföra beräkningen en gång och notera att den är utförd, s.k. chunking DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 43 / 68
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 23) Datalogi 1 Hösten 2012 44 / 68
Inkapsling, abstrakta datatyper Med växande program växer kravet på återanvänbarhet för programkod, kravet på att delprogram skall fungera i alla möjliga sammanhang och därmed kraven på modulär begriplighet, möjlighet att gömma modulers inre struktur, och minimala lättbegripliga kommunikationsgränssnitt mellan moduler. Antalet programmerare kan vara stort vid framtagandet av stora program. Därför är det viktigt med effektivitet (återanvända andras kod, generella, lätt anpassbara, lättbegripliga moduler). Det enda programmeraren skall behöva veta är vad modulen gör. Ansvaret för att modulen gör rätt ligger hos implementatören. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 45 / 68
Moduler Modularisering sker genom abstraktion. De moduler vi hittills diskuterat är funktioner och procedurer. För att funktioner och procedurer skall passa som moduler gäller utöver modulär begriplighet att de skall vara minimala, dvs att varje procedur/funktion utför endast en väl avgränsad uppgift och att modulen har ingångar endast för det som verkligen behövs för uppgiften och att resultatet är enbart det eftersökta. Man skiljer också mellan procedurer vars uppgift utförs genom bieffekter och funktioner vars utförande ger ett resultat som levereras till omgivningen antingen genom ett funktionsvärde eller genom parametrar om det aktuella språket inte tillåter funktioner att leverera komplexa resultat. Generellt sett skall värden levereras antingen genom funktionsvärde eller via parametrar. Aldrig genom en kombination av dessa. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 46 / 68
Moduler... Om funktioner i det aktuella språket kan leverera komplexa värden skall endast funktioner användas då ett i datorn representerbart resultat förväntas. Standard Pascal och Scheme har inget modulbegrepp (utöver funktions- och procedurabstraktioner). I Scheme kan man läsa in filer med definitioner när som helst i ett program. I Pascal är en vanlig utvidgning s.k. Units. Dessa är filer som delas in i två delar av de reserverade orden INTERFACE och IMPLEMENTATION. Allt som definieras i gränssnittsdelen- oftast funktions- och procedurhuvuden - syns i det anropande programmet, men det som finns i implementationsdelen - hjälpfunktioner/procedurer/datastrukturer och funktions- /procedurkroppar - syns inte. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 47 / 68
Moduler... Detta är inspirerat av modernare språks modulfaciliteter. I vissa fall kan konceptuellt sammanhörande datastrukturer, funktioner och procedurer föras samman i en modul så att det program som öppnar modulen får tillgång till alla datastrukturer/funktioner/ procedurer i paketet. Även här gäller regeln om minimalitet. Modulen skall då hantera ett koncept, t.ex. trigonometriska funktioner eller vektorer i rymden. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 48 / 68
Moduler... import math def spacevector (x, y, z): def scale(s): return spacevector (s * x, s * y, s * z) def add(v): return spacevector (x + v( getx ), y + v( gety ), z + v( getz )) def sub(v): return spacevector (x - v( getx ), y - v( gety ), z - v( getz )) def length(): return math.sqrt(x * x + y * y + z * z) def dotprod(v): return (x * v( getx )) + \ (y * v( gety )) + \ (z * v( getz )) DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 49 / 68
Moduler... def op(msg, arg = None): if msg == get : return x, y, z elif msg == getx : return x elif msg == gety : return y elif msg == getz : return z elif msg == add : return add(arg) elif msg == sub : return sub(arg) elif msg == length : return length() elif msg == dotprod : return dotprod(arg) else: print( No such command:, msg) return op DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 50 / 68
Moduler... Betraktar man exemplet med vektorer i rymden kan man konstatera att operationerna är grundläggande för typen vector och man kan betrakta typen vector som bestående av alla element som kan tillverkas med hjälp av tripler av reella tal. Typen tillsammans med en eller flera konstruktorer och de grundläggande operationerna kan bilda en abstrakt datatyp. Även för abstrakta datatyper gäller minimalitet: Datastrukturen skall endast innehålla exakt det som krävs. Operationsmängden skall också innehålla endast det som hör samman med typen, och helst bara de grundläggande konstruktorerna, selektorerna och operationer. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 51 / 68
Moduler... Om man behöver hjälpstrukturer/funktioner skall dessa helst döljas för omgivningen så att man inte frestas använda dem direkt. Sådan användning av hjälpstrukturer/funktioner och objektens inre struktur kan ha svåröverskådliga följder. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 52 / 68
Moduler... flyttfunktion namnfunktion zoomfunktion wind stängfunktion scrollfunktion scrollfunktion sizefunktion DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 53 / 68
Moduler... Båda typerna av modul som nu diskuterats finns i flera andra språk, ADA, Simula (vassare), SmallTalk (abstyp, men vassare), C++ (vassare), Eiffel (vassare), Java (vassare) m.m. I vissa språk finns det endast i utvidgningar av olika slag. Bland de vassaste Pascalvarianterna är Borland (Turbo) Pascal. Det nya mode-språket Java har vad man kallar interface (gränssnitt), en sorts signaturer (en slags minsta gemensam nämnare, alla måste uppfylla minst de stipulerade kraven). En modul som implementerat ett gränssnitt tvingas att tillhandahålla åtminstone den i gränssnittet stipulerade funktionalteten. Viktigast är abstraktion och gömmande av detaljer. Man gömmer detaljer för att slippa veta mer än hur man använder modulen och för att undvika fatala misstag. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 54 / 68
Polymorfi Polymorfi (många skepnader) är egentligen en mängd olika abstraktionsmekanismer och en indelning skulle kunna se ut så här: polymorfi universell ad hoc parametrisk inclusion coersion overloading DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 55 / 68
Parametrisk polymorfi Parametrisk polymorfi är svår att skilja från generik, men det finns en skillnad. Parametrisk polymorfi betyder att en funktion (procedurer) accepterar ett antal olika typer av parametrar, medan en generisk funktion/procedur/datastruktur vid instansiering ger en ny funktion/procedur/datastruktur som är specialanpassad till den aktuella typen. Parametrisk polymorfi har vi i fördefinierade funktioner i många språk, där den aktuella typen ger val av funktion som till slut hanterar problemet. Write/WriteLn i Pascal accepterar godtyckliga utskrivbara värden, vilka konverteras till text och skrivs på fil/skärm. En hel mängd med olika procedurer finns i bakgrunden för att konvertering skall ske på rätt se. Parametrisk polymorfi finns i ML, som accepterar godtyckliga typer som argument till funktioner om ingen bearbetning av värden sker. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 56 / 68
Parametrisk polymorfi... Exempel: fun id x = x; fun first (x,y) = x; fun first (x::y) = x; fun second (x,y) = y; fun second (x::y) = y; DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 57 / 68
Generik Generiska funktioner och procedurer och även typer finns i många språk, t.ex. Java och ADA. Enklast är ett exempel med en tänkt utbyggnad av Pascal. FUNCTION id <T>(i: T): T; VAR t1 : T; BEGIN id := i END; FUNCTION f<t>(i:t; PROCEDURE todo(var j:t)): T; BEGIN todo(i); f := i END; DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 58 / 68
Generik... FUNCTION intid := id <Integer>; FUNCTION RealF := f <Real>; DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 59 / 68
Monomorfi Parametrisk polymorfi innebär abstraktioner där information om parametertypen inte är uttömmande. Motsatsen till polymorfi är monomorfi. Monomorfi föreligger i statiskt typade språk som Pascal, C. Undantag är fördefinierade procedurer och funktioner som abs, eof, eoln (Pascal). Övriga statiskt typade språk har i huvudsak monomorfi, men många har mekaismer för parametrisk polymorfi. Tex har Simula viss, begränsad parametrisk polymorfi, ML kräver inte att en typ skall bestämmas om inte typberoende operationer ingår i algoritmen till en funktion, Scheme har parametrisk polymorfi (define (f x) (cond ((atom? x)...) ((number? x)...) (...))) DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 60 / 68
Overloading (överladdning) samma namn för många olika funktioner. Systemet avgör vilken funktion som skall anropas baserat på indatatypen. T. ex. fungerar +, och på alla typer av tal (i de flesta av språken) och mängder (Pascal). I vissa varianter av Standard ML finns overloading (NJSML) och det finns även i ADA, C++ och Java. Exempel: (Pascal) heltalsnegering (int int) flyttalsnegering (real real) heltalssubtraktion (int int int) flyttalssubtraktion (real real real) mängddifferens (set set set) DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 61 / 68
Omgivningsoberoende överladdning Inparametrarnas typ avgör vilken funktion som anropas vid varje enskilt anrop. Tillämpas i t.ex. Pascal och ML, exempel: Abs(i) (int int) Abs(r) (real real) Omgivningsberoende överladdning: I ADA gäller normalt för / att (int int int) eller (real real real) beroende på inparametertyperna men man kan i någon omgivning deklarera / t ex som (int int real) varvid denna lokala överladdning av funktionen anropas istället för (int int int)-varianten i den aktuella omgivningen. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 62 / 68
Parametriserade typer Parametriserade typer är typer som accepterar typer som argument och genererar en ny typ. Parametriserade typer är abstraktioner av abstraktioner, vars instanser är abstraktioner där en familj av typer ersatts av en typ. Det som ligger närmast till hands för exempel är de generiska listorna i ML: type intlist = int list; där intlist är en instans av den inbyggda generiska listtypen a list. I Java finns det inbyggt i språket att alla datatyper ärver typen Object. Allt är m a o subtyper (i någon mening) till denna typ. Fullt polymorfa lagringsstrukturer tillhandahålls för listor, träd, stackar, köer,... DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 63 / 68
Typinferens Monomorf typinferens: fun even n = n mod 2 = 0; fun plus m n = m + n; int bool even n? = plus mod 0 int m? n + n 2 int m n DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 64 / 68
Typinferens... fun incr m = m + 1; incr m + m 1 Polymorf typinferens = operationen OK trots att entydig info om inparametertyper inte finns, men det finns en entydig relation mellan in- och utdata. Exempel: fun id x = x; fun fst x y = x; id fst x x x y x DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 65 / 68
Typkonvertering måste ske (om möjligt) då en operation kräver en viss typ av argument men erhåller ett värde av en annan typ. Pascal har automatisk konvertering från integer till real i ett antal fall. Exempel: VAR r: Real; i: Integer; i := 12; r := i / 5; Här konverteras i s värde till 12.0 och 5 till 5.0 eftersom flyttalsdivision kräver att operanderna är flyttal. Resultatet läggs i variabeln som r refererar till. i := r / 5 blir fel eftersom 5 konverteras till 5.0 och r / 5.0 ger ett flyttal, men någon automatisk konvertering till heltal finns inte i Pascal. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 66 / 68
Typkonvertering... I Simula hade det gått bra eftersom resultatet trunkeras till ett heltal. I ML går ingendera varianten eftersom typkonvertering sker explicit: real int genom floor som trunkerar och int real genom funktionen real. I ADA finns en mängd funktioner med samma namn som typen för konvertering till en viss typ, men ingen implicit konvertering. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 67 / 68
Subtyper Subtyper finns i en mängd olika skepnader. Den enklaste är den som finns i Pascal. TYPE weekday = (mon, tue, wed, thu, fri, sat, sun); workday = mon.. fri; weekendday = sat.. sun; natural = 0.. MaxInt; smallint = -255.. 255; smallletter = a.. z ; Man kan i Pascal definiera subtyper till alla diskreta typer. Alla sådana blir då delintervall av den ursprungliga domänen. Alla operationer som finns i den ursprungliga typen finns även tillgängliga för subtypen. Man säger att subtypen ärvt alla operationer. I vissa språk kan man lägga till attribut (egenskaper) och modifiera operationsmängden (Simula, Smalltalk, C++, Borland Pascal, Eiffel, m fl). DA2001 (Föreläsning 23) Datalogi 1 Hösten 2012 68 / 68