Föreläsning 1 i Programmeringsparadigm Programmeringsparadigm : Vad menas med programmeringsparadigm? Två definitioner från Webster’ s New World dictonary : paradigm n. [< Gr. para-, besides + deigma, example] 1. an example or modell I vetenskapasteori: Bakomliggande tankemodell för samhörande teorier. Ex i fysiken. I datalogi: Bakomliggande tankemodell för olika sätt att skriva och utforma dator-program. Olika programmeringsspråk kan grupperas i olika paradigmer. program, programme n. [< Gr. pro-, before + graphein, skriva] 1. A list of events, pieces, performers, etc, as of an entertainment 2. A plan of procedure v.t to schedule in a program I datalogi : föreskrift, en beskrivning av vad en dator skall göra. När använder man olika paradigm i datalogi? Vid konstruktion av programmeringspråk. Ett visst programmeringsspråk tillhör ett visst paradigm. Vissa språk (säger sig vara) multi-paradigm-språk. När man "kodar". Även när man "designar" (utfomar) program (metoder som "Vattenfallsmetoden" och UML är rätt knutna till olika paradigm). När man studerar algoritmer spelar kanske paradigm mindre roll. Olika paradigm kan ofta användas för att beskriva samma algoritm, men det kan vara olika "bekvämt". Datalogins paradigm? Hur många paradigm finns det? Olika författare har olika definitioner. T ex i boken Tucker, Noonan: Programming languages Principles and paradigms talar man om imperativ , OO (objekt-oriented, objekt-inriktad), funktionell, logisk, händelsestyrd (event-driven) och jämlöpande (concurrent) paradigm. Medan Ravi Sethi : Programming Languages mest betonar de fyra första. Gränserna är ej skarpa, element från flera paradigmer kan finnas i samma språk. Ett modernt språk som Java är ett OO-språk, men man kan om man envisas användas som ett imperativt språk (men man har då ringa glädje av bibliotekten) och de flesta Java-program är händelsestyrda och jämlöpande programmering är möjlig i Java. Vilka paradigmer används? Ända fram till 1980-talet var imperativ programmering helt dominerande, på 1990-talet slog OO igenom (30 år efter det att OO uppfanns) . Varför kunna olika paradigm? KTH credo : Vetenskap och konst. TH ska förvalta och förnya (varifrån?) tekniken. För att kunna förmedla detta detta måste studierna syssla med teori och vetenskap och hämta ideer från forskning, inte bara syssla med "hur man gör för närvarande". Paradigmen ej helt oberoende. Kunskap i t ex Haskell leder till bättre Java-program. Paradigm ger perspektiv. Kanske blir det ett paradigmskifte? Ex från datalogins historia: OO, kalkylblad, 5:e generationes datorer (flopp) från biologin : Darwin, DNA från fysiken : Gallilei och Newton, relativitesteorin och kvantmekaniken från lingvistik : Chomsky generativ grammatik, inne på 50-talet, numera lite ute. Icke-paradigm-aspekter på programmeringsspråk: Hårt typade språk: I princip oberoende av paradigm. Hårt typade språk : Man "tvingas" tänka sig in i olika typer, kompilatorn hittar många fel. Otypade språk: Full frihet Pekare (referenser): Oberoende av paradigm? Osynligt? Halvautomatiskt (Java)? Explicit (Pascal, C)? Vad är programmering? Tre aspekter ( inspirerat av Sten Henriksson, Lund): Programmering är en sorts matematik och logik. Acceptabla språk börjar väl med bättre funktionella språk? Körbara specifikation? Körbar Design? Bevis att programmen är korrekta. Passar bra med funktionella paradigmen och den logiska. Programmering är algoritmer. Vad är beräkningsbart? Går allt att göra? O(n). Turing maskiner mm. Programspråk (t o m paradigmer? ) sekundärt? Numerisk analys. Ganska paradimoberoende? Programmering är klassik ingenjörskonst. Nedbrytning av moduler. Gränsnitt, Design och implementation. Implementation, programspråk (t o m paradigmer? ) sekundärt? Programmering är bara en del av ett system. Design av systemet det viktiga. Design och implementation av programmet sekundärt. Att vara systemerare är "finare" (och mer välavlönat) än att vara programmerare. "ADB". Användargränssnittet, samverkan med hela systemet det viktiga. Översikt paradigmhistoria, se häftes baksida (endast i pappersupplagan). Denna kurs: Imperativa paradigmen Objektinriktade paradigmen Funktionella paradigmen Logik paradigmen Syntaxanalys av programspråk Internetprogrammering : ~0.4 p C-programmering i lp 2. Java som imperativt språk. : Återblick på OO och Java : ~1.8 p Haskell : ~1.4 p Prolog : ~1 pTeori, viss metod formulerad i tre olika paradigm : ~0.4 p i lp 2. Delar av kursstartsidan http://www.nada.kth.se/kurser/kth/2D1361/progp05/index.html: Kursbunt (preliminärt) : Finns till försäljning på Nadas studieexpedition. ● Del av Graham Hutton: Programming in Haskell. Ännu ej publiserad. Kommer att finnas som särtyck genom tillmötesgående av författaren. ● Paul Brna : Prolog Programmingkursbok i logikprogrammering. ● Laborationer i 2D1350 Programmeringsparadigm. ● Kompletterande material i 2D1350 Programmeringsparadigm Alternativa böcker för kursdelen om funktionell programmering : ● Jeroen Fokker: Functional Programming. (Finns till försäljning på Nadas studieexpedition). 144 sidor varav ca 60 ingår i kursen Unix. ● M.M.T.Chakravarty, G. C. Keller : An Introduction to Computing ISBN 1 -74009-404-2. Trevlig, elemntär,lätt bok på 144 sidor, inte så dyr. Använder Haskell för att intoducera datalogi. Även en del om Unix. Laborationer : (I kursbunten, dock ej lab i C och i internet.): * Introduktion till Haskell. * Ett program för schack. * Att komma igång med Prolog redovisas ej * Släktrelationer (Prolog) * Listprogram, pargenerering (Prolog) * Tidernas knepigaste problem (Prolog) * Stabila äktenskap (Prolog) Gör vecka ==42 redovisa senast 12 oktober * Danska räkneord (läsperiod 2) * Lab i C (läsperiod 2) * Lab i internet( läsperiod 2) Tentamina : Skriftlig i läsperiod 2, tisdagen den 8 november 08.00-13.00. Godkänt på kursen <= Godkänd tentamen och godkända redovisade labbar. Extentor feån 4p-kursen... Planerade föresläsningar .... paradigm ide’ och semantik Imperativ Simulering av vonNeuman-dator CPU styrning ALU Beräkning (evaluering) av uttryck Primärminne Kod (funktioner, procedurer, subrutiner..) Tilldelning Flödeskontroll Variabler, aggregat av variabler, lokala / statiska /på heapen OO := Sekvens ; Snurror Alternativ Imperativ med objekt och arv CPU styrning ALU Beräkning (evaluering) av uttryck Primärminne Kod (funktioner, procedurer, subrutiner..) Tilldelning Flödeskontroll Variabler Funktionell Objekt, aggregat med variabler OCH metoder := Sekvens ; Snurror Alternativ Matte (funktioner) som programmeringsspråk Beräkning (evaluering) av uttryck, ofta med funktioner A -> B Logisk Kod (def av funktioner och typer) Logik (predikat, funktioner -> Bool) som programmeringsspråk Beräkning (evaluering) av predikat, ofta med förslag hur logiska varaibler skall instansieras -> Bool Händelsestyrd Jämnlöpande Kod (def av predikat) Användarprocess som styr Programexekveringen ( lyssnare i java) Flera process eller trådar (Thread i Java) som styr varandra, synkronisering, moniorer mm Kort (personlig) karaktärisik, något om kursinnehåll: Imperativ : 1990: Så har man alltid gjort och alla andra gör så här! Dessutom kan jag redan! "Självklart" att man instruerar datorn i vilken ordning saker skall göras. Programmering som simulering. I verkliga livet går tiden, i datorn programmet. Avspeglar datorns konstruktion. I denna kurs ~0.4 p i språket C i lp 2 och internetprogrammering( kan ses som egen paradigm) ~0.4 p i lp 2. OO (objektorienterad, objekt inriktad) : Simuleringsynen ännu mer betonad. Utveckling av imperativa pardigmen, men delvis inkompatibelt. Nära hur "vanliga" männsikor ser på värden, värden består av objekt av olika sorter (klasser) med både egenskaper (attribut) och ofta egna sätt att göra saker (metoder). Klasserna kan ordnas i hirarkier, där vissa gemensamma attribut och metoder kan ärvas. Funktionell: Ung = matte; Varför lära sig programmera när man redan kan matte/funktioner? Matematik har mångahundraåriga traditioner, mycket är redan klart. Välgjorda språk, generella och ortogonala konstruktioner, "Hög nivå", korta "program", inga sidoeffekter. dvs svaret på frågan får man? / kan man? är i regel JA! Men går det inte lite väl sakta? Används det? Man börjar på detta sätt i Göteborg, Luleå, Umeå, Linköping, KTH före ca 1995, SU (mat-datalogisk), Oxford, m fl ställen. I denna kurs ~1.6 p i språket Haskell Logik: Ung =logik; Varför lära sig programmera när man redan kan logik/relationer? Logik har hundraåriga traditioner, "hög nivå". Ren logik programmering nog en utopi, i praktiken tillgrips kompromisser. "Hög nivå", mycket korta "program" Men fattar man vad som händer igentligen? Men går det inte lite väl sakta? Prolog populärt i AI (artificiell intellegens). I denna kurs ~1.4 p i språket Prolog. Händelsestyrd: Många program skall ju göra nåt annat än bara "räkna ut nåt", dvs samverka med verkligheten. Egen paradigm ? Ex: Grafiska användargränssnitt (GUI). Jämlöpande : "Naturligt" att saker och ting kan ske parallellt. CPU : kostar ju litet, varför inte använda hundratals, så man slipper vänta? Egen paradigm ? Samma sak som händelsestyrd? Synkronisering och utbyte av data, hur? "Ju flera kockar ju sämre soppa"? Ett tentamensproblem löst i imperativ Java, OOJava, i funktionella språket Haskell och i logikspråket Prolog: En kurs har två moment, tentamen på vilket ges betyg 0 .. 5, och laborationer med tre laborationer vilka kan ges betyget ’G’ eller ’_’. Slutbetyg ges till de personer som har ’G’ på alla tre labbarna och minst betyg 3 på tentan. Slutbetyget blir då lika med tentabetyget. Skriv ett program som ger som resultat en betygslista med betyg för de personer som är godkända. Indata en sträng "<namn>,<betyg tenta>.>G/_ för varje godkänd labb>" Utdata : Trycks på std.out Exempel på körning: ..>java SlutbetygShort Siv 5 Eva 3 */ "Per,5.G_G" "Siv,5.GGG" "Eva,3.GGG" Imperativa paradigmen: Imperativ Java, kort version: public class SlutbetygShort { // // // // Java as an (almost) imperative language: main static, no objekts, but substring, indexOf, equals are OO-methods; call of static procedure would be indexOf(arg[i]), ’.’) instead of arg[i].indexOf(’.’) etc. public static void main (String [] arg) { for (int i = 0; i < arg.length; i = i+1 ) { String name = (arg[i]).substring(0 ,(arg[i]).indexOf(’,’)); int eGrad = Integer.parseInt( (arg[i]).substring((arg[i]).indexOf(’,’)+1, (arg[i]).indexOf(’.’))); String labs = (arg[i]).substring((arg[i]).indexOf(’.’)+1); if ( (labs.equals("GGG")) && (eGrad >= 3)) { System.out.println(name + " " + eGrad); } } } } Primärminne i name eGrad labs public static main lokala variabler på "stacken" variabler på allokeras när main kör "heapen" allokeras när main kör med new Version med poster = "records " = "structures" = klasser utan instansmetoder. Java som imperativt språk i ett något större program: class Student { // "imperative record/structure" NB. no methods !! String name ; int eGrad; // grade on examination String labs;// G is passed laboration, examples GGG, G_G } class Grade { // "imperative record/structure" NB. no methods !! String name; int grade; } public class Slutbetyg { // Java as an imperative language // all methods static, no instance methods // // // // // // // // // But; Java arrays and strings has been used for convenience; arrays and string in Java must be treated as objects In Pascal and other imperative languages you donot have to do lines marked by // not in Pascal also standard methods for strings have been used for convenience; in an imperative language (arg[i]).indexOf(’,’) would have looked as indexOf(arg[i], ’,’) static Student [] student; static Grade [] grade; public static void main (String [] arg) { student = new Student [arg.length]; // grade = new Grade [arg.length]; // makeStudents(arg, student); makeGrades(student, grade); printGrades(grade); not in Pascal not in Pascal // More functional style : // student = students(arg); // grade = grade(student); } static void makeStudents(String [] arg, Student [] st) { for (int i = 0; i < arg.length; i = i+1 ) { st[i] = new Student(); // not in Pascal (st[i]).name = (arg[i]).substring(0 ,(arg[i]).indexOf(’,’)); (st[i]).eGrad = Integer.parseInt( (arg[i]).substring((arg[i]).indexOf(’,’)+1, (arg[i]).indexOf(’.’))); (st[i]).labs = (arg[i]).substring((arg[i]).indexOf(’.’)+1); } } static void makeGrades(Student [] st, Grade [] gr) { for (int i = 0; i < st.length; i = i+1 ) { gr[i] = new Grade(); // not in Pascal gr[i].name = new String (st[i].name); // newString not in Pascal if ( (((st[i]).labs).equals("GGG")) && ((st[i]).eGrad >= 3)) { gr[i].grade = st[i].eGrad; } else { gr[i].grade = -1; } } } static void printGrades(Grade [] gr) { for (int i = 0; i < gr.length; i = i+1 ) { if ((gr[i]).grade > 2) { System.out.println((gr[i]).name + " " + (gr[i]).grade); } } } } Primärminne stacken statiska variabler student koden heapen name eGrad labs ... main makestudent makeGrades printGrades grade name grade ... lokala variabler, som finns när en viss procedur kör statiska variabler student grade med refererade variabler som skapas med new under körningen "metoder" dvs procedurer, alla static void Objektorienterade paradigmen: Objektorienterad Java: public class SlutbetygOO { // Java as an OO language // Objects of type Student has instance methods. static Student [] student; public static void main (String [] arg) { student = new Student [arg.length]; for (int i = 0; i < arg.length; i = i+1 ) { student[i] = new Student(arg[i]); if (student[i].isPassed()) { System.out.println(student[i].getName() + " " + student[i].getFinalGrade()); } } } } class Student { String int String boolean name ; eGrad; labs; passed; // grade on examination // G is passed laboration, examples GGG, G_G // passed course public Student(String input) { name = input.substring(0 ,(input).indexOf(’,’)); eGrad = Integer.parseInt( input.substring(input.indexOf(’,’)+1, input.indexOf(’.’))); labs =input.substring(input.indexOf(’.’)+1); passed = (labs.equals("GGG")) && (eGrad >= 3); } public String getName() { return name; } public int getFinalGrade() { if (passed) { return eGrad; } else { return -1; } } public boolean isPassed() { return passed; } } Primärminne stacken statiska variabler student statisk kod heapen name eGrad labs passed Student getName getFinalGrade ispassed main "metod" procedurer, static void ... ... lokala variabler, som finns när en viss procedur kör statisk variabel VARJE Student-objekt innehåller nu både "data" med refererade och (begreppsmässigt) variabler som skapas med new metoder (kod) under körningen student Varför är OO ett framsteg jämfört med traditionell imperativ programmering? Jo, antag att programmet skall generaliseras för flera olika sorters studenter, t ex teknologer som skall ha betyg 3 4 5 och universitetsstudenter med betyg G VG och .. I den traditionella imperativa lösningen måste vi då på en massa ställen stoppa in if- eller case-satser eftersom metoderna skall fungera olika, olika sorters variabler skall finnas osv: if student == Teknolog ... else if student == Universitetsstudent .. else if .... Detta är jobbigt och svårt och måste i större program göras på en massa ställen varje gång vi anpassar programmet för ytterligare en ny sorts studenter. Med OO skriver vi en Student-super-klass som innehåller det som är gemensamt för alla sorters studenter, döper om vår gamla Student klass till Teknolog (som ärver nya Student) och en ny klass Universitetsstudent (som ärver nya Student) osv. De gamla programmet behöver inte ändras alls! För varje ny studentsort behöver vi bara skriva en ny sub-klass, som innehåller allt nytt på ett och samma ställe. Mycket bekvämt. Detta är finessen med arv och dynamisk bindning, dvs att alla gör en viss metod "på sitt sätt". Funktionella paradigmen: Problemformulering : Skriv ett program slutbetyg :: [(String, Int,[Char])] -> [(String, Int)] som givet en lista av typ [(String, Int,[Char])] med personers namn, tentamensbetyg och labresultat retunerar slutbetyg för de personer som skall ha godkänt på kursen. Exempel : res = [("Per", 5, [’G’, ’_’, ’G’]), ("Siv", 5, [’G’, ’G’, ’G’]), ("Eva", 3, [’G’, ’G’, ’G’])] ...> slutbetyg res [("Siv",5),("Eva",3)] Version a : Elementär Haskell utan användning några högre ordningens funktioner eller listomfattning. slutbetyg [] = [] slutbetyg ((namn, tenta, lablista):ntls) | lablista == [’G’, ’G’, ’G’] && tenta >= 3 (namn, tenta) : slutbetyg ntls | otherwise Version b : Haskell = = slutbetyg ntls med inbyggda funktionerna map och filter slutbetyg lista = map f (filter p lista) where f (namn, tenta, _ ) = (namn, tenta) p (_, tenta, lablista) = lablista == [’G’, ’G’, ’G’] && tenta >= 3 Version c : Haskell med listomfattning (hela programmet är på 1-2 rader !!) slutbetyg lista = [ (namn,tenta) | (namn,tenta,[’G’, ’G’, ’G’])<- lista , tenta>=3] Logiska paradigmen: En Prolog -lösning : Exempel på körning : slutbetyg([r(per,5,[g,n,g]),r(siv,5,[g,g,g]),r(eva,3,[g,g,g])], Slubs = [slutbetyg(siv,5),slutbetyg(eva,3)] ? ; no. Slubs). slutbetyg([], []). slutbetyg([r(Namn, Tenta, [g, g, g]) | Ntls ], [slutbetyg(Namn, Tenta) | Ntls1]) :Tenta >=3, slutbetyg( Ntls, Ntls1). slutbetyg([r(_, _, Lablista) | Ntls ], Ntls1) :% Om man inte testar member(n, Lablista), % för underkänt får man slutbetyg( Ntls, Ntls1). % ytterligare felaktiga svar % vid backtracking -1 poäng slutbetyg([r(_, Tenta, _) | Ntls ], Ntls1) :% Ingen rekursion för underkända Tenta <3,slutbetyg( Ntls, Ntls1) % - 5 päng