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