Typsystem Typsystem finns i alla programmeringsspråk. Avsikten med typsystem är att kontrollera att uttryck är säkra i den bemärkelsen att innebörden i operanderna är klar och inte är motsägelsefull och att betydelsen av en operation är väldefinierad 38 + pelle, där 38 kan vara heltal, reellt tal eller en textsträng och pelle är en textsträng. Möjliga betydelser t.ex.: konkatenera textsträngarna 38 och pelle behandla pelle som ett heltal och lägg detta till 38 I vissa programmeringsspråk är typningen dynamisk d.v.s. att variabler inte har någon typ utan endast värden har typ. Då måste typen hos uttryck framgå av hur man använder variablerna och kontrollen sker under körning av programmet. Scheme har dynamiskt typsystem. (define (f x) (+ 2 (square x))) (define (square a) (* a a)) (f "kalle") DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 1 / 19 DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 2 / 19 Här kommer felet att upptäckas först då man försöker applicera funktionen * på argumenten kalle och kalle. Motsvarande evalueringsträd blir + 2 * kalle Multiplikationsoperatorn kräver numeriska argument. kalle Andra språk har statisk typning, vilket innebär att all typkontroll sker vid översättningstillfället (kompileringstillfället eller interpretationen), varvid ingen tveksamhet får finnas avseende operationers typöverensstämmelse. Både Pascal och ML är statiskt typade språk. Ex (Pascal): PROGRAM test; FUNCTION square(a: Real): Real; square := a * a; FUNCTION f(x: Real): Real; f := 2 + square(x); WriteLn(f(4), f(3.1)); END. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 3 / 19 DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 4 / 19
Typekvivalens Ex (ML): fun f(x: real) = 2.0 + square(x); fun square(a:real) = a * a; f(3.1); (* går bra, men.. *) f(3); (* går inte bra, men f(real 3) går *) f("kalle"); (* går inte bra *) Om en operation som tar en typ av argument anropas med en annan typ av argument måste de två argumenttyperna i någon mening vara lika för att en typkontroll skall vara genomförbar. Vad menas med att typerna är lika? Ex (Pascal): TYPE atype = ARRAY [1..3] OF Integer; btype = ARRAY [1..3] OF Integer; VAR a: atype; b: btype; c: btype; d: ARRAY [1..3] OF Integer; Här är b och c av samma typ, medan a, b och d är av olika typ. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 5 / 19 DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 6 / 19 Man kan inse nödvändigheten av typspecifikation i Pascal vid användande av underprogram (moduler). FUNCTION f(a: ARRAY [1..3] OF Integer): Integer; är en omöjlighet eftersom ingen typ är ekvivalent med a s typ. Ovanstående typekvivalens kallas namnekvivalens, vilket betyder att typernas namn, inte deras struktur, avgör ekvivalensen. TYPE T1 = Integer; T2 = Integer; VAR a : T1; b : T2; Trots att T1 och T2 är definierade som en typ av Integer är inte T1 och T2 samma typ eftersom namnen är olika. a + b är inte en tillåten operation. Två variabler har samma typ om de deklareras i samma deklarationssats. Ex (Pascal): VAR a, b: ARRAY [3..9] OF Integer; c: ARRAY [3..9] OF Integer; Här har a och b samma typ men inte a och c resp b och c. Man skulle kunna betrakta strukturen hos en typ i stället för namnet på typen och betrakta två typer som lika om deras struktur överensstämmer, oavsett namnet och platsen för specifikation. Man måste då rekursivt analysera strukturen hos typerna för att kunna avgöra om dessa är lika eller inte. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 7 / 19 DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 8 / 19
Definition (strukturell ekvivalens): Två typer T och T är typekvivalenta omm de har samma värdemängd. Det betyder att T och T är typekvivalenta ( ) om 1. T och T båda är primitiva och identiska, t ex: boolean boolean och 1..35 1..35 2. T = A B och T = A B och A A och B B 3. T = A + B och T = A + B samt A A och B B eller A B och B A 4. T = A B och T = A B och A A och B B TYPE i = 1..10; a = ARRAY [ a.. z ] OF ARRAY [Boolean] OF i; b = ARRAY [Boolean] OF i; c = ARRAY [ a.. z ] OF b; FUNCTION f(x: a; b: Boolean; ch: Char): i;... FUNCTION g(x: c; b: Boolean; ch: Char): i;... DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 9 / 19 DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 10 / 19 f och g är strukturellt ekvivalenta men inte namnekvivalenta, ty: f har typen a Boolean Char i, g har typen c Boolean Char i, A = a Boolean Char, B = i, A = c Boolean Char, B = i. B B. A A om a c. a = Char (Boolean i) och c = Char (Boolean i), så a c. Ett språk kallas typkomplett om alla värden kan hanteras utan speciella restriktioner för vissa värdetyper. Pascal är inte typkomplett eftersom funktioner inte kan returnera alla typer av värden som resultat. Man kan t ex inte få funktioner, procedurer, poster eller kontinuerliga listor som resultat av funktioner. Sådana värden (för vilka någon speciell restriktion gäller) kallas andra klassens värden. Värden, för vilka inga speciella restriktioner gäller, kallas första klassens värden. Scheme och ML är typkompletta. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 11 / 19 DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 12 / 19
Uttryck Pascal: TYPE pairptr = ^pair; pair = RECORD a, b: sometype; FUNCTION swap(p: pairptr): pairptr;... swap := p; ML: fun swap (a, b) = (b, a);! (... ) är en konstruktor!! mönstermatchning! Scheme: (define (swap x) (list (cadr x) (car x))) Uttryck kallas de programdelar vars beräkning resulterar i att ett värde levereras till omgivningen. Vi delar in uttrycken i: literaler aggregat funktionsanrop villkorliga uttryck konstanters och variablers värden DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 13 / 19 DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 14 / 19 En literal är en symbol för ett värde av någon typ, t ex 3.14-78 4711 a januari true 2/7 Konstanters värden. I Pascal kan man definiera konstanter först i deklarationsdelen i varje modul. CONST pi = 3.141592; firstmonth = Januari ; Man definierar en identifierare som identifierar ett värde, givet av en literal. I andra språk kan det vara tillåtet att skriva ett uttryck i stället för en literal. Variablers värden. Då man i Pascal deklarerar ett namn, t ex: VAR anumber: Integer; kommer namnet anumber att identifiera det minnesutrymme där ett värde av typen Integer lagras. Minnesutrymmet kallas variabel och namnet (identifieraren) används för att komma åt variabeln. För att ändra variabelns värde används en tilldelningsoperator, ofta :=, t ex: anumber := 10. För att avläsa variabelns värde används identifieraren i något uttryck, t ex: IF anumber > 3 THEN... Villkorliga uttryck är uttryck vars värde beror av ett eller flera andra uttryck. Ett villkorligt uttryck måste konstrueras så att det alltid lämnar ett värde som resultat. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 15 / 19 DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 16 / 19
Ex (Scheme): (cond ((< x y) (if (< y z) y (if (< x z) z x))) (else (if (< z y) y (if (< x z) x z)))) Ex (ML): case x < y of true => if y < z then y else if x < z then z else x false => if z < y then y else if x < z then x else z; Ex (Simula): IF x < y THEN (IF y < z THEN y ELSE IF x < z THEN z ELSE x) ELSE (IF z < y THEN y ELSE IF x < z THEN x ELSE z); DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 17 / 19 Aggregerande uttryck skapar vid evaluering aggregat. Ex (Scheme): (list x y z) Ex (ML): [x, y, z] (* lista med tre element *) Ex (ML): (x, y, z) (* tupel med tre attribut *) Ex (ML): {x=7, y=5, z=13} (* post med fälten x, y och z *) I ML finns alltså tre olika konstruktorer för aggregat: [ ] för listor, där alla element skall vara av samma typ, ( ) för tupler, där elementen får vara av olika typ, { } för poster, där elementen har namn och får vara av olika typ. Obs att tupler är poster med anonyma fält, och att alla sorters poster är av typen kartesisk produkt, medan listorna är rekursivt definierade typer. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 18 / 19 Funktionsanrop sker genom att en funktion appliceras på sina argument (en lista av aktuella parametrar): Scheme: (funktionsnamn arg 1 arg 2... arg n ) En Schemefunktion kan konstrueras för att återsända varje typ av resultat. (define f (lambda (n) (lambda (m) (max m n)))) (f 5) ;;; ger en funktion int int ((f 5) 7) ;;; ger ett heltal Pascal: funktionsnamn(arg 1, arg 2,..., arg n ) En Pascalfunktion kan endast återsända atomiska resultat. DA2001 (Föreläsning 23) Datalogi 1 Hösten 2010 19 / 19