Nya typer Konstruerare, selektorer och predikat Rekursiva datatyper Datatyper nr 10 Nya typer Konstruerare, selektorer och predikat Rekursiva datatyper
Datatyper Hur ska vi på bästa sätt kunna modellera objekt i den verkliga världen?? Ofta behöver man definiera egna datatyper Programmen blir lättare att läsa och förstå. Ökar möjligheterna för typkontroll. Kan användas vid mönstermatchning
Uppräkningsbara typer datatype traffic_light = green | amber | red | redamber; datatype traffic_light con green: traffic_light con amber: traffic_light con red: traffic_light con redamber: traffic_light fun nextstate green = amber | nextstate amber = red | nextstate red = redamber | nextstate redamber = green; val nextstate = fn : traffic_light -> traffic_light
Datatypsdeklaration Skapar en ny typ Skapar nya konstruerare Syntax konstruerarkonstanter, identifierare Syntax datatype type_constructor = value_constructor1 | value_constructor2 | … | value_constructorn
Strukturerad datatyp Kopplar konstrueraren till ett värde av någon given typ datatype coords = coords of real * real * real datatype coords con coords : (real * real * real) -> coords Syntax datatype type_constructor = value_constructor1 [of type_expression1] | value_constructor2 [of type_expression2] | … | value_constructorn [of type_expressionn]
Ta isär dataobjekt Använd mönstermatchning val origin = coords (0.0, 0.0, 0.0); val origin = coords (0.0, 0.0, 0.0) : coords val point_max = coords (100.0, 100.0, 100.0); val point_max= coords(100.0,100.0,100.0):coords fun midpoint (coords (x1,y1,z1)) (coords (x2,y2,z2)) = coords ((x1+x2)/2.0,(y1+y2)/2.0,(z1+z2)/2.0); val midpoint = fn : coords -> coords -> coords midpoint origin point_max; val it = coords (50.0, 50.0, 50.0) : coords
datatype kontra type En datatyp (datatype) En typsynonym (type) En ny typ kan inte jämföras med underliggande typ Ärver ej operationer Kan jämföras för likhet (i den mån underliggande typ kan) Kan ha flera konstruerare Kan ha flera olika underliggande typer (som också kan vara egna datatyper) En typsynonym (type) Ett nytt namn för en existerande typ Har samma värden som den namngivna typen
Unionstyp En datatyp med flera konstruerare motsvarar en union av olika typer datatype numb = itype of int | rtype of real datatype numb con rtype : real -> numb con itype : int -> numb Ett värde av typen numb är antingen ett heltal (konstruerat med itype) eller ett reellt tal (konstruerat med rtype) - rtype 4.0; > val it = (rtype 4.00000) : numb - itype 34; > val it = (itype 34) : numb
Matchning av olika värden För att använda de olika värdena matchar vi mot konstrueraren fun makeint (itype n) = n | makeint (rtype r) = floor r val makeint = fn : numb -> int fun addnumb (itype n) (itype m) = itype (n+m) | addnumb (itype n) (rtype r) = rtype (real n + r) | addnumb (rtype r) (itype m) = rtype (r + real m) | addnumb (rtype r) (rtype s) = rtype (r + s) val addnumb = fn : numb -> (numb -> numb) - addnumb (rtype 4.0) (itype 23); > val it = (rtype 27.0000) : numb
Egna typfunktioner Den definierade typen kan vara en typfunktion som tar typer som argument. Då har typen (prefixa) argument till typnamnet vid deklarationen. datatype 'a queue = que of 'a list; datatype 'a queue con que : 'a list -> 'a queue Det är en eller flera typvariabler datatype ('a,'b) pair = pair of 'a * 'b datatype ('a , 'b) pair con pair : ('a * 'b) -> (('a , 'b) pair)
Användning Vid användning av typen eller konstrueraren måste typen ha argumenten. Dessa binds till typvariablerna. que [2,3,4]; > val it = (que [2,3,4]) : int queue pair (4,true); > val it = (pair (4,true)) : (int , bool) pair fun idqueue (q : (int * int) queue) = q; > val idqueue = fn : (int * int) queue -> (int * int) queue
En kö En kö är en sekvens av värden där man sätter in i ena änden och tar ut ur andra. Vi kan definiera olika typer av funktioner som arbetar med köer. Funktioner för att skapa köer val empty = que nil; val empty = (que nil) : 'a queue; fun enter e (que es) = que (e::es); val enter = fn : 'a -> 'a queue -> 'a queue enter 2.0 (enter 7.5 empty); val it = (que [2.00000, 7.50000]) : real queue;
Selektorer Speciella funktioner för att välja ut delar av en kö. exception Remove and Rest; fun remove (que nil) = raise Remove | remove (que es) = last es; > val remove = fn: 'a queue -> 'a fun rest (que nil) = raise Rest | rest (que (e::nil)) = (que nil) | rest (que (e::es)) = let val (que q2) = rest (que es) in que(e::q2) end; > val rest = fn: 'a queue -> 'a queue
Predikat Funktioner som avgör hur kön är uppbyggd fun isempty (que es) = null es; > val isempty = fn: 'a QUEUE -> bool
Konstruerare vs. funktioner Skillnader: Konstruerar kan matchas i mönster Funktioner beräknar ett resultat utifrån definitionen Konstrueraren bygger ett värde Likheter: Tar argument Kan skickas som parameter, mappas,.. Ej ordnade
Rekursiva datatyper En kö som är antingen tom eller minst ett element lagt sist i en kö datatype 'a queue = empty | enter of 'a * 'a queue; con empty: 'a queue con enter= : ('a * 'a queue) ->'a queue enter (5, enter (3, enter (1,empty))); val it = enter(5,enter(3,enter(1,empty))): int queue
Selektorer exception Remove and Rest; fun remove empty = raise Remove | remove (enter (e, empty)) = e | remove (enter (e, q)) = remove q; val remove = fn: 'a queue -> 'a fun rest empty = raise Rest | rest (enter (e, empty)) = empty | rest (enter (e,q)) = enter (e, rest q); val rest = fn: 'a queue -> 'a queue;
Predikat fun isempty q = q = empty; val isempty = fn: 'a queue -> bool val q1 = enter (5, enter (3, enter (1,empty))); > val q1 = enter (5, enter (3, enter (1,empty))): int queue remove q1; > val it = 1:int rest q1; > val it = enter(5,enter(3,empty))): int queue