Referentiell transparens. Programkonstruktion. Moment 10 Om sidoeffekter In/utmatning och imperativ programmering. Sidoeffekter.

Relevanta dokument
Referentiell transparens. Programmeringsmetodik DV1 Programkonstruktion 1. Moment 10 Om sidoeffekter In/utmatning och imperativ programmering

Programkonstruktion. Moment 11 Om sidoeffekter In/utmatning och imperativ programmering. PKD 2011/12 moment 11 Sida 1 Uppdaterad

"Referentiell transparens"

SI-möte #10, Programkonstruktion och Datastrukturer

Programkonstruktion. Tentamen,

Programmeringsmetodik DV1, Programkonstruktion del 1 Tentamen,

Programkonstruktion. Tentamen,

Programkonstruktion. Tentamen,

Former av rekursion. Programkonstruktion. Moment 5 Mera om rekursion. Fakultetsfunktionen. Största gemensamma delare (repris!

DD1361 Programmeringsparadigm. Carina Edlund

Programmeringsmetodik DV1 Programkonstruktion 1. Moment 4 Om rekursion. PK1&PM1 HT-06 moment 4 Sida 1 Uppdaterad

Summera godtyckligt antal tal. Programkonstruktion. Moment 4 Om rekursion. Fullständigt resonemang för summeringen. Analys av summeringsproblemet

Programmera i C Varför programmera i C när det finns språk som Simula och Pascal??

Labb i Datorsystemteknik och programvaruteknik Programmering av kalkylator i Visual Basic

Så fungerar en dator

Föreläsning 6: Introduktion av listor

Programkonstruktion och datastrukturer. Moment 9 Om högre ordningens funktioner. PKD 2010/11 moment 9 Sida 1 Uppdaterad

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

Datatyper och kontrollstrukturer. Skansholm: Kapitel 2) De åtta primitiva typerna. Typ Innehåll Defaultvärde Storlek

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

Omtentamen (del 1, 6 högskolepoäng) i Programkonstruktion och datastrukturer (1DL201)

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Programkonstruktion och datastrukturer. Moment 5 Om generella datastrukturer och träd. PKD 2011/12 moment 5 Sida 1 Uppdaterad

i LabVIEW. Några programmeringstekniska grundbegrepp

Imperativ programmering. Föreläsning 2

Övning2. Variabler. Data typer

Funktionell programmering DD1361

Introduktion till formella metoder Programmeringsmetodik 1. Inledning

Programmeringsmetodik DV1 Programkonstruktion 1. Moment 9 Om högre ordningens funktioner. PK1&PM1 HT-06 moment 9 Sida 1 Uppdaterad

Klassdeklaration. Metoddeklaration. Parameteröverföring

Programkonstruktion och datastrukturer. Moment 9 Om högre ordningens funktioner. PKD 2011/12 moment 9 Sida 1 Uppdaterad

Programkonstruktion och datastrukturer. Formell verifiering eller hur man bevisar att program gör rätt utan att testa dem

Tabeller. Programkonstruktion. Moment 8 Om abstrakta datatyper och binära sökträd. Implementering av tabellen. Operationer på tabellen

TDIU01 - Programmering i C++, grundkurs

LÖSNINGSFÖRSLAG TENTAMEN PROGRAMMERING I ETT FUNKTIONELLT SPRÅK ML, 5P

Datastrukturer. Erik Forslin. Rum 1445, plan 4 på Nada

SCB :-0. Uno Holmer, Chalmers, höger 2 Ex. Induktiv definition av lista. // Basfall

Övning från förra gången: readword

kl Tentaupplägg

Deklarationer/definitioner/specifikationer

Repetition i Python 3. Exemplen fac. Exemplen fac motivering. Exemplen fac i Python

Programmering I Tobias Wrigstad fredag, 2009 augusti 28

Tabeller. Programkonstruktion. Moment 8 Om abstrakta datatyper och binära sökträd. Specifikationer för tabellfunktionerna. Operationer på tabellen

Föreläsningsanteckningar, Introduktion till datavetenskap HT S4 Datastrukturer. Tobias Wrigstad

Programmering A. Johan Eliasson

Programmering, grundkurs, 8.0 hp HI1024, HI1900 etc., Tentamen TEN1. Måndagen den 10 januari 2011,

Grundläggande datalogi - Övning 1

Instruktioner - Datortentamen TDDD73 Funktionell och imperativ programmering i Python TDDE24 Funktionell och imperativ programmering del 2

Datalogi I, grundkurs med Java 10p, 2D4112, Fiktiv tentamen, svar och lösningar och extra kommentarer till vissa uppgifter 1a) Dividera förs

Repetition i Pascal. Exemplen fac. Exemplen fac i Pascal. Exemplen fac motivering. Orginalet

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Muddy. Funktioner / metoder. Punktnotation. Evalueringsordning

Alla datorprogram har en sak gemensam; alla processerar indata för att producera något slags resultat, utdata.

Visual Basic, en snabbgenomgång

Programmering i C++ En manual för kursen Datavetenskaplig introduktionskurs 5p

Beräkningsvetenskap föreläsning 2

Imperativ programmering. Imperativ programmering konstruktioner i Lisp. Datastrukturer (kap ) arraystruktur poststruktur

Erfarenheter från labben

Generiska konstruktioner. Kursbokens kapitel 13

Webbsidor och webbservrar

Att deklarera och att använda variabler. Föreläsning 10. Synlighetsregler (2) Synlighetsregler (1)

EDAA20 Programmering och databaser. Mål komprimerat se kursplanen för detaljer. Checklista. Föreläsning 1-2 Innehåll. Programmering.

Inledande programmering med C# (1DV402) Summera med while"-satsen

C++ Funktioner 1. int summa( int a, int b) //funktionshuvud { return a+b; //funktionskropp } Värmdö Gymnasium Programmering B ++ Datainstitutionen

Föreläsning 3-4 Innehåll. Diskutera. Metod. Programexempel med metod

EDAA20 Programmering och databaser. Mål komprimerat se kursplanen för detaljer. Om att lära sig programmera. Föreläsning 1-2 Innehåll.

Programmeringsmetodik DV1 Programkonstruktion 1. Moment 8 Om abstrakta datatyper och binära sökträd

Tentamen. Datalogi I, grundkurs med Java 10p, 2D4112, Lördagen den 30 november 2002 kl , salar E33, E34

F4. programmeringsteknik och Matlab

TDDE44 Programmering, grundkurs

Språket Python - Del 1 Grundkurs i programmering med Python

Bakgrund. Bakgrund. Bakgrund. Håkan Jonsson Institutionen för systemteknik Luleå tekniska universitet Luleå, Sverige

Objektorienterad programmering i Java I. Uppgifter: 2 Beräknad tid: 5-8 timmar (OBS! Endast ett labbtillfälle) Att läsa: kapitel 5 6

Föreläsning 3-4 Innehåll

GPT föreläsning 8. Förra veckan: Man kan ta tiden på en sorterad teckensträng Förra gången: Problemlösning på lägre nivå kan sortera funktioner

String [] argv. Dagens Agenda. Mer om arrayer. Mer om arrayer forts. String [] argv. argv är variabelnamnet. Arrayer och Strängar fortsättning

Imperativ och Funktionell Programmering i Python #TDDD73. Fredrik Heintz,

Grundkurs Programmering

Pascal... Pascal. Pascal... Pascal...

Att förstå hur man konstruerar modulära program Att kunna skapa nya funktioner Att förstå hur data skickas mellan funktioner

Inledande programmering med C# (1DV402) 27+15=42 1 (22)

I dag: Blockstruktur, omgivningar, problemlösning

Föreläsning 5: Introduktion av pekare

Tentamen i Introduktion till programmering

[] Arrayer = Indexerad variabel

Pascal. reserverade ord fördefinierade funktioner och procedurer egendefinierade funktioner, procedurer och objekt

Användarhandledning Version 1.2

Tentamen *:58/ID100V Programmering i C Exempel 3

Programmeringsteknik I

Föreläsning 1 & 2 INTRODUKTION

Datalogi för E Övning 3

Objektorienterad programmering Föreläsning 8. Copyright Mahmud Al Hakim Agenda (halvdag)

Programmeringsteknik med C och Matlab

Tenta (TEN3) i kursen 729G04 Programmering och diskret matematik 5 feb 2016, kl 14:00-18:00

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.

Datalogi, grundkurs 1. Lösningsförslag till tentamen

Föreläsning 3: Typomvandling, villkor och val, samt textsträngar

TDDC74 Lab 04 Muterbara strukturer, omgivningar

Pythons standardbibliotek

C++ - En introduktion

kl Tentaupplägg

Transkript:

Programkonstruktion Moment 10 Om sidoeffekter In/utmatng och imperativ programmerg Referentiell transparens I ren funktionell programmerg kan man byta lika mot lika utan att programmets funktion ändras. Detta kallas referentiell transparens. Orsaken är att en beräkng te har någon effekt annat än att beräkna ett värde (om man bortser från tids/mnesåtgång). f x*g y kan bytas mot g y*f x. f x ^ f x kan bytas mot val fx = f x fx^fx end Det sista bytet lönar sig resursmässigt om beräkngen av f x tar lång tid eller har ett stort objekt som värde. Ett sådant byte kan t.o.m. göras automatiskt av ML-systemet. PK 2008/09 moment 10 Sida 1 Uppdaterad 2006-09-06 PK 2008/09 moment 10 Sida 2 Uppdaterad 2006-09-06 Inmatng Hittills har all /utmatng av data gått via ML-systemets användargränssnitt. I praktiken räcker te det programmen måste själva kunna mata /ut data t.ex. till/från filer. Låt oss anta att det fns en funktion readle med spec.: readle x TYPE : unit -> strg SIDE-EFFECTS: En rad läses från termalfönstret. POST: en sträng med den rad som lästs. EXAMPLE: readle() = "Hej\n" om man skriver raden "Hej\n" på tangentbordet. Körexempel: - readle(); Hej, hopp. > val it = "Hej, hopp.\n" : strg Sidoeffekter Vad blir readle()^readle()? Låt oss anta att användaren först skriver raden "Hej" sedan "hopp". (Varför slutar strängarna med \n?) readle()^readle() > "Hej\n"^readle() > "Hej\n"^"hopp\n" > "Hej\nhopp\n" Observera att readle()!readle()! Man kan alltså te byta readle()^readle() mot val rl = readle() rl^rl end Det beror på att readle te bara beräknar ett värde utan också läser en ny rad från termalen vid varje anrop readle har en sidoeffekt. Anta anrop och deras bördes ordng blir viktig. PK 2008/09 moment 10 Sida 3 Uppdaterad 2006-09-06 PK 2008/09 moment 10 Sida 4 Uppdaterad 2006-09-06 Sekvenserg När sidoeffekter fns blir beräkngsordngen mycket viktig. Tänk på att ML beräknar uttryck från vänster till höger (och ifrån och ut). Ibland kan man vilja beräkna flera uttryck efter varandra endast för deras sidoeffekter utan att bry sig om värdet. För detta ändamål fns ML-konstruktionen e1 ; e2 ;... ; en-1 ; en vars värde är värdet av en, men som dessutom först beräknar e1 t.o.m. en-1. e1;e2;...;en-1;en är mengsfull bara om beräkngen av e1 t.o.m. en-1 har sidoeffekter. (Obs att ; även avslutar uttryck som man matar till ML. ; som sekvensoperator måste stå om parenteser,..end eller dylikt.) PK 2008/09 moment 10 Sida 5 Uppdaterad 2006-09-06 Utmatng prt x TYPE: strg -> unit SIDE-EFFECTS: x skrivs ut på termalfönstret. POST: () EXAMPLE: prt "Hej\n" = () och skriver samtidigt raden "Hej\n" på termalfönstret. prt "Hej\n";prt "Hej\n" > ();prt"hej\n" (och "Hej\n" skrivs ut.) > ();() (och "Hej\n" skrivs ut.) > () Alltså prt "Hej\n" = prt "Hej\n" trots det kan man te byta prt "Hej\n";prt "Hej\n" mot val ph = prt "Hej\n" ph;ph end prt beräknar te bara ett värde utan skriver också på termalen. En ny rad skrivs vid varje anrop prt har en sidoeffekt. Anta anrop och deras bördes ordng blir viktig. PK 2008/09 moment 10 Sida 6 Uppdaterad 2006-09-06

In/utmatng i ML TextIO För /utmatng (I/O) fns olika bibliotek i ML, bl.a. biblioteket TextIO för - och utmatng av text. För att slippa skriva TextIO. före alla namn på funktioner och värden i detta bibliotek kan man använda deklarationen open TextIO; i sitt program. Den gör att ML automatiskt söker i biblioteket TextIO efter namn den te känner igen annars. (Detta fungerar med alla bibliotek, även t.ex. Strg och List.) Man kan använda flera open-deklarationer. Jag förutsätter i fortsättngen att man använt deklarationen open TextIO. (Obs! open är gen ersättng för load.) PK 2008/09 moment 10 Sida 7 Uppdaterad 2006-09-06 Strömmar Vid I/O krävs omfattande admistration, bl.a. skall filer lokaliseras och man behöver hålla reda på hur långt i en fil man har läst/skrivit. Läspekare frithiof.txt: Der växte uti Hildgs gård två plantor under fostrarns vård. Ej Norden förr sett två så sköna, de växte härligt i det gröna. TextIO fns abstrakta datatyper stream och outstream kallade strömmar. All formation rörande I/O fns i strömmarna. För I/O till termalfönster fns i TextIO två fördefierade strömmar stdin av typ stream och stdout av typ outstream. PK 2008/09 moment 10 Sida 8 Uppdaterad 2006-09-06 Skapa strömmar openin s TYPE: strg -> stream PRE: s skall vara namnet på en fil som fns. POST: En stream kopplad till filen s. SIDE-EFFECTS: Olika anrop till openin ger olika strömmar. EXAMPLE : openin "frithiof.txt" openout s : strg -> outstream PRE: s skall vara namnet på en fil som går att skriva/skapa. POST: En outstream kopplad till filen s. SIDE-EFFECTS: Filen s skapas om den te fns. Olika anrop till openout ger olika strömmar. EXAMPLE : openout "nyfil" PK 2008/09 moment 10 Sida 9 Uppdaterad 2006-09-06 Ett urval funktioner för matng (1) putle is TYPE: stream -> strg POST: Nästa rad från strömmen is (kl. \n), eller tom sträng om get kunde läsas (t.ex. filslut) SIDE-EFFECTS: Läspekaren för is flyttas fram. Exempelfunktionen readle kan defieras så här: fun readle() = putle stdin; put1 is TYPE: stream -> char option POST: SOME c om nästa tecken i strömmen är c, NONE om get kunde läsas (t.ex. filslut). SIDE-EFFECTS: Läspekaren för is flyttas fram. closein is TYPE: stream -> unit POST: (). SIDE-EFFECTS: Avslutar användngen av strömmen is PK 2008/09 moment 10 Sida 10 Uppdaterad 2006-09-06 Ett urval funktioner för matng (2) putall is TYPE: stream -> strg POST: Resterande text i strömmen is till filslut. SIDE-EFFECTS: Läspekaren för is flyttas fram. endofstream is TYPE: stream -> bool POST: true om läsngen av strömmen is har nått till slutet av filen, false annars. SIDE-EFFECTS: ga. PK 2008/09 moment 10 Sida 11 Uppdaterad 2006-09-06 Exempel på läsng från ström (* readtolist f TYPE: strg -> strg list PRE: f är namnet på en fil som kan läsas POST: En lista av raderna i filen f *) fun readtolist f = (* readtolistaux is TYPE: Stream -> strg list POST: En lista av återstående rader i is *) (* VARIANT: återstående rader i is *) fun readtolistaux is = if endofstream is then (closein is; []) putle is :: readtolistaux is readtolistaux (openin f) PK 2008/09 moment 10 Sida 12 Uppdaterad 2006-09-06

Termerg av rekursion vid läsng När man läser data från en ström i ett rekursivt program så bryts i allmänhet rekursionen av filslut. Man kan te veta i förväg hur många rekursiva anrop som skall ske utan att veta hur strömmen ser ut. Det vet man normalt te nan den är läst! Desutom är det prciellt omöjligt om man läser från en ström som skapas successivt (t.ex. en ström som läser från ett tangentbord.) Som rekursionsvariant kan man ange t.ex. (* VARIANT: oläst längd på strömmen is *) Om funktionen läser från is och rekursionen avslutas vid filslut. PK 2008/09 moment 10 Sida 13 Uppdaterad 2006-09-06 Två vanliga fel... (* readtolist f TYPE: strg -> strg list PRE: f är namnet på en fil som kan läsas POST: En lista av raderna i filen f *) (* VARIANT: återstående rader i f *) fun readtolist f = val is = openin f if endofstream is then [] putle is :: readtolist f readtolist öppnar en ny ström vid varje anrop och läser därför första raden i filen om och om igen. Inga strömmar stängs någons. PK 2008/09 moment 10 Sida 14 Uppdaterad 2006-09-06 Ett urval funktioner för utmatng (1) output(os,s) TYPE: outstream*strg -> unit POST: () SIDE-EFFECTS: Strängen s skrivs ut på strömmen os. Ett urval funktioner för utmatng (2) output1(os,c) TYPE: outstream*char -> unit POST: () SIDE-EFFECTS: Tecknet c skrivs ut på strömmen os. flushout os TYPE: outstream -> () POST: (). SIDE-EFFECTS: Skriver ut bufferten för strömmen os closeout os TYPE: outstream -> unit POST: (). SIDE-EFFECTS: Avslutar användngen av strömmen os Den byggda funktionen prt skulle kunnat defieras så här: fun prt s = (output(stdout,s);flushout stdout); PK 2008/09 moment 10 Sida 15 Uppdaterad 2006-09-06 PK 2008/09 moment 10 Sida 16 Uppdaterad 2006-09-06 Tillägg till beftliga filer openout skapar en ny fil eller skriver över en beftlig fil. Man kan också vilja lägga till ny formation i slutet av en beftlig fil. openappend s TYPE: strg -> outstream PRE: s skall vara namnet på en fil som går att skriva elller skapa. POST: En outstream kopplad till filen s. SIDE-EFFECTS: Filen s skapas om den te fns. Skrivngen börjar i slutet av filen. Olika anrop till openappend ger olika strömmar. Tillägg till filer "exempel Om vi har en fil testut.txt, med nehåll: Hej, Hopp I det gröna och gör: - val x = openappend "testut.txt"; > val x = <outstream> : outstream - output(x,"sade Frithiof\n"); - closeout x; så kommer testut.txt att nehålla: Hej, Hopp I det gröna sade Frithiof PK 2008/09 moment 10 Sida 17 Uppdaterad 2006-09-06 PK 2008/09 moment 10 Sida 18 Uppdaterad 2006-09-06

I/O av annat än text Vill man mata /ut data av annan typ än strg måste man omvandla den till till/från strängar först. Omvandlgen måste man programmera själv om te byggd funktion fns (t.ex. Int.toStrg) Konverterg från strängar är besvärligt. I allmänhet har strängen olika typer av formation blandade efter varandra, t.ex: "beräkna 1+23*4 slut". Ur denna sträng skulle man vilja få: strängen "beräkna", ta 1, tecknet +, ta 23, tecknet *, ta 4, och strängen "slut". Dessutom vill man kanske ha 1+23*4 representerat som ett träd! Detta problem kallas syntaxanalys eller parsng. Parsng behandlas i senare kurser. PK 2008/09 moment 10 Sida 19 Uppdaterad 2006-09-06 Metodik för utvecklg av program med i/o Tänk noga på i vilken ordng saker och tg utförs Försök dela upp programmet i en del som utför all /utmatng och en annan del som te alls utför någon i/o. Testa alla data som läses lita te på att de är riktiga! För teraktiva program (program som arbetar i dialog med en användare) bör man dessutom tänka på: Programmet får te kunna avbrytas pga fel så att användaren förlorar data. Tänk igenom dialogen med användaren strukturera programmet efter den. PK 2008/09 moment 10 Sida 20 Uppdaterad 2006-09-06 En kalkylator i ML Skriv en enkel fyrfunktionskalkylator i ML! Den skall läsa ett tal, en operation och ett tal till och visa resultatet. Därefter skall man kunna utföra kedjeräkng med nya operationer och tal. Skriv ett tal: 3 Skriv ett tal: 3.5 Skriv en operation: + Skriv en operation: d Skriv ett tal: 4 Felaktig operation! Resultatet är: 7.0 Skriv en operation: / Skriv en operation: + Skriv ett tal: 0 Skriv ett tal: 5.2 Fel! Resultatet är: 12.2 Skriv ett tal: 0 Skriv en operation: c Skriv en operation: q Skriv ett tal: abc Felaktigt tal! PK 2008/09 moment 10 Sida 21 Uppdaterad 2006-09-06 Tillståndsdiagram När man planerar programmet kan man göra ett tillståndsdiagram över dialogen. Avsluta Börja Läs ett tal calc Läs en operation readop Skriv ut resultatet prtresult Läs ett tal och beräkna doop Programmet skrivs som en tillståndsmask som motsvarar PK 2008/09 moment 10 Sida 22 Uppdaterad 2006-09-06 diagrammet. Varje tillstånd motsvaras av en funktion i programmet. Programstrukturen Programkoden visas i top-down ordng med huvudfunktionerna först och hjälpfunktionerna sist. I programfilen måste funktionerna ligga i motsatt ordng eftersom en funktion måste defieras nan de används. Funktionerna i tillståndsmasken är ömsesidigt rekursiva. Programmet leds med deklarationerna: load "Real"; open TextIO; PK 2008/09 moment 10 Sida 23 Uppdaterad 2006-09-06 PK 2008/09 moment 10 Sida 24 Uppdaterad 2006-09-06

Tillståndsmasken (1) (* calc x TYPE: unit -> unit SIDE-EFFECTS: Huvudfunktion i kalkylatorn *) fun calc() = readop(readnum()) (* readop x TYPE: real -> unit SIDE-EFFECTS: Läser en operation i kalkylatorn *) and readop x = (prt "Skriv en operation: " ; case putle stdin of "q\n" => () "c\n" => calc() opr => case selectop opr of SOME f => doop(x,f) NONE => (prt "Felaktig op.\n"; readop x)) PK 2008/09 moment 10 Sida 25 Uppdaterad 2006-09-06 Tillståndsmasken (2) (* doop(x,f) TYPE: real*(real*real -> real) -> unit SIDE-EFFECTS: Läser en tal och utför en operation i kalkylatorn *) and doop(x,f) = (prtresult(f(x,readnum())) handle _ => (prt "Fel!\n"; calc())) (* prtresult x TYPE: real -> unit SIDE-EFFECTS: Skriver resultat i kalkylatorn *) and prtresult x = (prt ("Resultatet är: " ^ Real.toStrg x ^ "\n"); readop x); PK 2008/09 moment 10 Sida 26 Uppdaterad 2006-09-06 Välj operation (* selectop x TYPE: strg -> (real*real -> real) option POST: Om x är namnet på en känd operation returneras SOME f, där f är en funktion som utför operationen. NONE annars. EXAMPLE: selectop "+\n" = SOME (op +) *) fun selectop "+\n" = SOME (op +) selectop "-\n" = SOME (op -) selectop "*\n" = SOME (op * ) selectop "/\n" = SOME (op /) selectop _ = NONE; Läs tal (* readnum x TYPE: unit -> real SIDE-EFFECTS: Läser från termalen POST: Ett läst flyttal *) fun readnum () = (prt("skriv ett tal: "); case Real.fromStrg (putle stdin) of SOME x => x NONE => (prt "Felaktigt tal\n"; readnum ())); PK 2008/09 moment 10 Sida 27 Uppdaterad 2006-09-06 PK 2008/09 moment 10 Sida 28 Uppdaterad 2006-09-06 Återblick: gentg ändras... I ren funktionell programmerg kan man aldrig ändra någontg bara skapa nytt. Detta är en förutsättnig för att byta lika mot lika. - val x = [1,2,3,4]; > val x = [1, 2, 3, 4] : t list - rev x; > val it = [4, 3, 2, 1] : t list - x; x är oförändrad efter > val it = [1, 2, 3, 4] : t list anropet av rev x! - val y = 1; > val y = 1 : t - fun f x = x+y; > val f = fn : t -> t - val y = 2; > val y = 2 : t - f 2; f använder den gamla > val it = 3 : t bdngen av y! PK 2008/09 moment 10 Sida 29 Uppdaterad 2006-09-06 Modifierbara celler ML ger möjlighet att skapa datastrukturer som verkligen kan ändras. ref är en datatypskonstruktor som nästan beter sig som datatype 'a ref = ref of 'a; ref 3 kallas en referens till värdet 3. (Kallas också cell, box, låda). För att komma åt refererade värden använder man funktionen! fun! (ref x) = x;!x kallas derefererg av x. Referenser kan ändras med den fixa funktionen :=: r := v TYPE: 'a ref*'a -> unit SIDE-EFFECTS: Värdet i r ändras till v. POST: () EXAMPLE: val x = ref 3;!x = 3 x := 2; Nu är!x = 2 PK 2008/09 moment 10 Sida 30 Uppdaterad 2006-09-06

Ingentg är säkert längre... Använder man referenser så kan man i allmänhet te längre byta lika mot lika. - val y = ref 1; > val y = ref 1 : t ref y är nu bunden till en referens till ett heltal. - val =!y; > val = 1 : t - fun f x = x+!y; Obs. blank mellan +! > val f = fn : t -> t - y := 2; - =!y; y är nu ändrad > val it = false : bool - f 2; f använder det nya > val it = 4 : t värdet! PK 2008/09 moment 10 Sida 31 Uppdaterad 2006-09-06 Ändrgar kan ske bakom ryggen Anrop av funktioner med sidoeffekter kan förändra data beräkngsordngen blir kritisk. (* bump x TYPE: t ref -> t SIDE-EFFECTS: Ökar nehåller i cellen x med 1. POST: Det nya värdet av x. *) fun bump x = (x :=!x + 1;!x); - val x = ref 1; > val x = ref 1 : t ref - bump x; > val it = 2 : t -!x; > val it = 2 : t Obs att (bump x)+!x och!x+(bump x) beräknar olika värden! PK 2008/09 moment 10 Sida 32 Uppdaterad 2006-09-06 Bdngsomgivngar och lagret Defitioner (val, fun) bder identifierare till värden. Bdngar kan aldrig ändras. Bdngsomgivngar är en samlg bdngar. Bdngsomgivngar kan skapas och försvna. Dessutom har ML ett lager (eng. store) som är en samlg celler. ref skapar celler som nehåller ett värde Innehål i celler kan ändras Lagret är en samlg celler Det fns bara ett lager och det försvner aldrig. - val y = ref 1; > val y = ref 1 : t ref y 1 PK 2008/09 moment 10 Sida 33 Uppdaterad 2006-09-06 Likhet och olikhet hos celler - val y = ref 1; > val y = ref 1 : t ref - val y' = y; > val y' = ref 1 : t ref - y := 2; - val = ref 2; > val = ref 2 : t ref - y = y'; > val it = true : bool - y = ; > val it = false : bool y y' 2 y 1 y y' y y' 1 2 2 PK 2008/09 moment 10 Sida 34 Uppdaterad 2006-09-06 Referenser från celler till celler - val x = ref 1; > val x = ref 1 : t ref - val y = ref 2; x 1 > val y = ref 2 : t ref - val = ref x; y 2 x 1 > val = ref ref 1 : t ref ref x 1 - val u = ref (!x); > val u = ref 1 : t ref y 2 u 1 y 2 får typ t ref ref en pekare till en annan cell! x 1 Referenser från celler till celler (forts.) x 1 -! := 3; u 1 y 2 x 3 - := y; u 1 - := ref 4; u 1 u 1 y 2 x 3 y 2 x 3 y 2 4 PK 2008/09 moment 10 Sida 35 Uppdaterad 2006-09-06 PK 2008/09 moment 10 Sida 36 Uppdaterad 2006-09-06

- := u; Skräpsamlg u 1 u 1 x 3 x 3 y 2 4 y 2 Cellen med värdet 4 är te åtkomlig längre den har blivit skräp. Skräp tas bort automatiskt med skräpsamlg (garbage collection). Alla sorters data i ML kan bli skräp te bara celler utan t.ex. listor men fenomenet märks kanske tydligast med celler. Tack vare skräpsamlgen fungerar det att ML-program arbetar med att ständigt konstruera nya objekt utan att någons ta bort gamla. PK 2008/09 moment 10 Sida 37 Uppdaterad 2006-09-06 4 Imperativ programmergsstil I imperativ programmergsstil arbetar man med att ändra nehål i celler snarare än bda identifierare. utföra beräkngar i steg (satser) som har sidoeffekter, snarare än som uttryck. (Enkla uttryck är ofta delar av satser.) utföra upprepngar med loopar snarare än rekursion. Imperativ programmergsstil är det normala i programspråk som Pascal, C, Java... Det som kallas variabler i dessa språk är normalt namngivna ref-celler. Uttryck av ref-typ i ML motsvarar Lvalues i C alltså något som kan tilldelas ett värde. C och andra imperativa språk derefererar (utför!-operationen på) variabler automatiskt när det behövs. PK 2008/09 moment 10 Sida 38 Uppdaterad 2006-09-06 Ett imperativt program (* abssqrt x TYPE: real->real POST: Kvadratroten av absolutbeloppet av x. *) fun abssqrt(x) = val x' = ref x if!x' < 0.0 then x' := ~ (!x') () ; < ; skiljer uttryck som fungerar som satser. Math.sqrt(!x') PK 2008/09 moment 10 Sida 39 Uppdaterad 2006-09-06 Loopar En loop upprepar ett uttryck (sats). while e1 do e2 Uttrycket e2 beräknas upprepade gånger så länge uttrycket e1 beräknas till true. Värdet av while är alltid (). Utan sidoeffekter är detta mengslöst eftersom e1 och e2 alltid skulle ge samma värden! Loopar är det normala sättet att utföra iteration i imperativa språk som Java och C (i stäl för svansrekursion som i ML). Detta uttryck nehåller en loop som skriver ut Hej igen! 10 gånger: val i = ref 1 while!i<=10 do (prt "Hej igen!\n"; i :=!i + 1) PK 2008/09 moment 10 Sida 40 Uppdaterad 2006-09-06 Analys av summergsproblemet (repris) Start. Låt summan vara 0. Är n=0? Nej. Ja. Addera n till summan. Subtrahera 1 från n. Stopp. Konstruktionen kallas för en loop. (Det spelar gen roll om vi adderar n+...+0 eller 0+...+n) PK 2008/09 moment 10 Sida 41 Uppdaterad 2006-09-06 Imperativ summergsfunktion (* sumupto TYPE: t -> t PRE: x >= 0 POST: 1+2+...+x *) fun sumupto x = val n = ref x val sum = ref 0 while!n > 0 do (sum :=!sum +!n; n :=!n - 1);!sum Samma funktion i funktionell variant: fun sumupto n = if n = 0 then 0 n + sumupto(n-1); PK 2008/09 moment 10 Sida 42 Uppdaterad 2006-09-06

Imperativ genomgång av listor (* countgreater(x,g) TYPE: t list*t -> t POST: Antal element i x som är större än g *) fun countgreater(x,g) = val l = ref x val n = ref 0 while not (null(!l)) do (if hd(!l) > g then n :=!n + 1 (); l := tl(!l));!n PK 2008/09 moment 10 Sida 43 Uppdaterad 2006-09-06 countgreater imperativ och funktionell fun countgreater(x,g) = (* imperativ *) val l = ref x val n = ref 0 while not (null(!l)) do (if hd(!l) > g then n :=!n + 1 (); l := tl(!l));!n fun countgreater(l,g) = (* funktionell *) if null l then 0 (if hd l > g then 1 0) + countgreater(tl l,g) PK 2008/09 moment 10 Sida 44 Uppdaterad 2006-09-06 Loopar och svansrekursion (* Med loop *) fun sumupto x = val n = ref x val sum = ref 0 while!n > 0 do (sum :=!sum +!n; n :=!n - 1);!sum (* Med svansrekursion *) fun sumupto x = sumuptoaux(x,0); fun sumuptoaux(n,sum) = if n > 0 then sumuptoaux(n-1,sum+n) sum PK 2008/09 moment 10 Sida 45 Uppdaterad 2006-09-06 Imperativ summerg av flyttalsvektor (* sumvector a TYPE: real vector -> real POST: Summan av elementen i a *) fun sumvector a = val sum = ref 0.0 val i = ref 0 while!i < Vector.length a do (sum :=!sum + Vector.sub(a,!i); i :=!i + 1);!sum PK 2008/09 moment 10 Sida 46 Uppdaterad 2006-09-06