Wprowadzenie do programowania paradygmaty programowania dr hab. inż. Mikołaj Morzy
plan wykładu wprowadzenie do języków programowania generacje języków programowania translacja, interpretacja, kompilacja paradygmaty programowania programowanie imperatywne programowanie proceduralne programowanie deklaratywne programowanie strukturalne programowanie obiektowe programowanie logiczne
co to jest język programowania? język programowania to systematyczny sposób przekazywania maszynie zadań do wykonania za pomocą języków programowania precyzyjnie zapisujemy algorytmy i inne zadania dla komputera dane + algorytm język programowania symbole słowa kluczowe syntaktyka semantyka program
syntaktyka i semantyka syntaktyka (składnia) opisuje struktury sterujące (pętle, przypisania, warunki) opisuje struktury danych (zmienne, rekordy) tworzy poprawne symbole do nazywania zmiennych definiuje sposób korzystania z interpunkcji definiuje sposób budowania poprawnych wyrażeń semantyka (znaczenie) określa znaczenie poprawnych składniowo wyrażeń
generacje języków programowania historię rozwoju języków programowania podzielono arbitralnie na 5 okresów/generacji poszczególne generacje opisują zaawansowanie struktur języka, czyli odpowiadają przyjazności poszczególnych języków
I generacja pierwsza generacja języków programowania to programowanie bezpośrednio w kodzie binarnym każdy typ komputera posiada własny kod (listę rozkazów procesora) nazywany kodem maszynowym każdy program musi być przepisany w konkretnym kodzie maszynowym 1000010110101010100010101011101010011010 1010101010101010010101010010101010010101 0101011111111111010101101111111100000010 1010101010101010101010101010010101001010
II generacja aby ułatwić programowanie, każdej kombinacji symboli 0 i 1 przypisano znaki mnemotechniczne języki operujące znakami mnemotechnicznymi nazywane są językami symbolicznymi lub asemblerami asembler jest tłumaczeniem kodu maszynowego, program nie musi być już pisany pod konkretny typ komputera mov bx, 12 mov ax, 10 add ax, bx mov [3987], 20 int 32
III generacja języki III generacji to języki wysokiego poziomu, w których znaki mnemotechniczne zastąpione niezależnym od maszyny kodem zbliżonym do języka naturalnego lub matematycznego języki wysokiego poziomu są uniwersalne istnieje tendencja do specjalizacji i orientacji języków int x := 0; for (int i=0; i++, i<0) loop x := tab[i] + tab[i-1]; end loop;
IV generacja języki IV generacji to środowiska graficzne generowania gotowych aplikacji na podstawie predefiniowanych modułów często rozszerzają funkcjonalność istniejących języków języki programowania obiektowego jako IV generacja
V generacja języki V generacji to języki programowania w logice, wykorzystujące sztuczną inteligencję, często pod postacią języka naturalnego lub języka zbliżonego do naturalnego mother(gaia,uranus). parents(cronus,rhea,zeus). female(persephone). male(apollo). mother(x,y) :- parents(_,x,y). female(x) :- mother(x,_). father(x,y) :- parents(x,_,y).
generacje języków: podsumowanie duża V generacja języki naturalne zrozumiałość IV generacja Delphi, PostScript, Visual Basic III generacja Java, C#, C++, Pascal, Fortran II generacja asembler I generacja kod maszynowy mała liczba instrukcji
a w rzeczywistości liceum 10 PRINT "HELLO WORLD" 20 END pierwszy rok studiów program Hello(input,output) begin writeln('hello World') end. ostatni rok studiów (defun hello (print (cons 'Hello (list 'World))))
a w rzeczywistości zawodowiec #include <stdio.h> void main(void) { char *msg[] = ("Hello ", "World"}; for (int i=0; i<2; ++i) printf("%s", msg[i]); printf("\n"); } administrator #include <stdio.h> #include <stdlib.h> main() { char *tmp; int i=0; tmp=(char *)malloc(1024*sizeof(char)); while (tmp[i]="hello World"[i++]); i=(int)tmp[8]; tmp[8]=tmp[9]; tmp[9]=(char)i; printf("%s\n",tmp); }
a w rzeczywistości haker #!/usr/local/bin/perl $msg="hello World\n"; if ($#ARGV > 0) { while(defined($arg=shift(@argv))) { $outfilename = $arg; open(file, ">".$outfilename) die "Can't write $arg"; print(file $msg); close(file) die "Can't close $arg: $!\n"; } else { print($msg); } doświadczony haker #include <stdio.h> #include <string.h> #define S "Hello World\n" main(){ exit(printf(s) == strlen(s)? 0 : 1); }
a w rzeczywistości wieloletni haker % cc o a.out ~/src/misc/hw/hw.c % a.out Hello World. guru-haker %cat Hello World. menadżer mail s "Hello World" bob@acme.com Bob, czy możesz napisać program który wypisuje na ekranie "Hello World"? Potrzebuję na jutro ^D
a w rzeczywistości menadżer wyższego szczebla % zmail jim Potrzebuję programu "Hello World" dziś po południu prezes % letter % letter Letter: Command not found. % mail To: ^X ^F ^C % help mail Help: Command not found. % cholera!!: Event unrecognized % logout
języki niskiego i wysokiego poziomu język niskiego poziomu to zbiór instrukcji wykonywanych bezpośrednio w procesorze język wysokiego poziomu ma wyższy poziom abstrakcji a składnia i słowa kluczowe służą ułatwieniu zrozumienia programu przez człowieka, kod języka wysokiego poziomu nie jest bezpośrednio zrozumiały dla komputera i wymaga przetłumaczenia do postaci języka niskiego poziomu
translacja translacja to proces tłumaczenia kodu w języku wysokiego poziomu na ciąg instrukcji zrozumiałych dla maszyny, która wykonuje kod translacja tłumaczy z języka źródłowego na semantycznie równoważny zapis w języku wynikowym program wykonujący translację to translator kompilator tłumaczy bezpośrednio na język maszynowy, kolejne uruchomienia programu nie wymagają powtórnej kompilacji, przykłady to C, C++, Pascal, Fortran interpreter tłumaczy kod źródłowy linia po linii, z pominięciem pliku wynikowego, każde uruchomienie programu to ponowna interpretacja, przykłady to JavaScript, Python, HTML, GnuPlot
translacja w praktyce unika się translacji bezpośrednio z kodu źródłowego do kodu maszynowego translacja wieloetapowa tłumaczenie z kodu źródłowego do asemblera tłumaczenie z asemblera na kod maszynowy zalety translacji wieloetapowej optymalizacja kodu łączenie (linkowanie) części programu zapisanych w innych językach programowania
jak powstaje program? algorytm programowanie język wysokiego poziomu kompilacja kod maszynowy
co to jest stos? stos (ang. heap) to struktura danych, w której nowe dane są dopisywane na wierzchu stosu, dane są też pobierane (czytane) jedynie z wierzchu stosu stos to magazyn o określonych rozmiarze pobieranie odbywa się w kolejności odwrotnej do stawiania zgodnie z porządkiem LIFO (last in first out) podstawowe operacje dopisz na stosie (ang. push): nowy element zostaje umieszczony na szczycie stosu odczytaj ze stosu (ang. pull): element zostaje zdjęty ze szczytu stosu
odwrotna notacja polska ONP to beznawiasowy zapis wyrażeń formalnych zaproponowany po raz pierwszy przez J. Łukasiewicza ze względu na łatwość obliczania wyrażeń arytmetycznych zapisanych w ONP jest często wykorzystywana w informatyce w ONP symbole operandów poprzedzają bezpośrednio symbol operatora (notacja przyrostkowa) a + b = a b +
przykłady wyrażeń w ONP ( a + b) * d a b + d * ( a + ( b* c) a b c*+ ( a + b)*( c + d) a b + c d +* (( a + b)*(( c + ( d + e)) ( e+ f ) ))) a b + c d e + + e f + ^ *
translacja wyrażeń do ONP założenia źródłowy zapis tłumaczonego wyrażenia arytmetycznego pojawia się na wejściu specjalnego automatu na wyjściu automat produkuje zapis w ONP wyrażenia wejściowego, wewnętrznie automat wykorzystuje stos wyrażenie arytmetyczne automat ze stosem ONP wyrażenia arytmetycznego model automatu ze stosem do translacji wyrażeń arytmetycznych
priorytety ograniczników w trakcie translacji w specjalny sposób traktuje się ograniczniki (symbole operacji arytmetycznych) ogranicznikom przypisany jest określony priorytet operator funkcja lg, sin, exp priorytet potęgowanie 1 0 * ~ 2 + - 3
algorytm działania automatu pobierz kolejne znaki wyrażenia arytmetycznego począwszy od lewej strony jeśli pobrany znak jest argumentem, prześlij na wyjście jeśli pobrany znak jest nawiasem otwierającym, odłóż znak na stosie jeśli pobrany znak jest nawiasem zamykającym, zdejmij ze stosu i prześlij na wyjście wszystkie znaki aż do napotkania pierwszego znaku nawiasu otwierającego włącznie jeśli pobrany znak jest operatorem, to szukaj na stosie operatora o wyższym priorytecie jeśli znajdziesz taki operator, to zawartość stosu prześlij na wyjście i odłóż na stos pobrany operator jeśli nie znajdziesz takiego operatora, to odłóż na stos pobrany operator w obu przypadkach przeszukuj stos do napotkania znaku nawiasu otwierającego lub do końca stosu (jeśli nawias nie występuje) jeśli nawias wystąpił i był też operator o wyższym priorytecie, to zdejmij zawartość stosu do nawiasu otwierającego, pozostawiając nawias na stosie
uwagi do algorytmu wyrażenie arytmetyczne posiada specjalny znacznik końca (wyróżniony znak) przetwarzanie zostaje zakończone w momencie napotkania znacznika końca nawiasy otwierające i zamykające nie są kopiowane na wyjście jeśli pobrany znak nie jest nawiasem, argumentem, operatorem lub znacznikiem końca, to algorytm zgłasza błąd
schemat blokowy algorytmu
przykład konwersji ((( a )) + b + d)*( d + e) a b d + + d e + * wejście stos wyjście ( ( ( ( ( ( ( ( ( a ( ( ( a ) ( ( ) ( + ( + b ( + b + ( + + d ( + + d ) ++ * * ( * ( d * ( d + * ( + e * ( + e ) * + *
zadanie samodzielne wykorzystaj podany algorytm do translacji poniższego wyrażenia do odwrotnej notacji polskiej (( a + b) (3* x + 7* y)) a b + 3 x*7 y *+
obliczanie wartości w ONP algorytm pobieraj kolejno symbole wyrażenia począwszy od lewej strony jeśli symbol jest liczbą (zmienną), to odłóż symbol na stos jeśli symbol jest operatorem, to pobierz dwa elementy ze stosu, wykonaj operację i odłóż wynik z powrotem na stosie kontynuuj do wyczerpania danych wejściowych obliczona wartość wyrażenia znajduje się na stosie
obliczanie wartości: schemat blokowy
obliczanie wartości ONP: przykład oblicz wartość wyrażenia 2 3 4 5 +*+ wejście stos 2 2 3 2 3 4 2 3 4 5 2 3 4 5 + 2 3 9 * 2 27 + 29
zadanie samodzielne oblicz wartość wyrażenia 2 7 + 3/14 3 4* + 2 / wejście stos 2 2 7 2 7 + 9 3 9 3 / 3 14 3 14 3 3 14 3-3 11 4 3 11 4 * 3 44 + 47 2 47 2 / 23.5
paradygmaty programowania paradygmat (gr. paradeigma: wzór, model, przykład) programowania to sposób patrzenia osoby programującej na przepływ sterowania i wykonywanie programu komputerowego różne języki programowania mogą wspierać różne paradygmaty
przykładowe paradygmaty programowania programowanie imperatywne deklaratywne proceduralne logiczne strukturalne obiektowe
imperatywne vs deklaratywne programowanie imperatywne program opisuje kolejne czynności które należy wykonać program specyfikuje w jaki sposób maszyna ma działać programowanie deklaratywne program opisuje cel, który ma zostać osiągnięty program specyfikuje wynik jaki maszyna ma uzyskać, ale nie określa sposobu uzyskania wyniku
programowanie imperatywne programowanie imperatywne to najbardziej podstawowy i naturalny sposób programowania, w którym program jest sekwencją instrukcji i poleceń dla komputera obliczenia są rozumiane jako sekwencja poleceń zmieniających, krok po kroku, stan maszyny, aż do uzyskania pożądanego wyniku stan maszyny to zawartość pamięci operacyjnej, rejestrów i znaczników procesora przykłady: kod maszynowy, asembler, Pascal, Ada, C
programowanie proceduralne programowanie proceduralne polega na podziale zadania na mniejsze podzadania, które stanowią fragmenty wykonujące ściśle określone operacje poszczególne fragmenty są implementowane niezależnie od siebie w postaci podprogramów (procedur, funkcji) komunikacja między podprogramami odbywa się poprzez przekazywanie danych (lub wskaźników) możliwa jest także komunikacja przez zmienne globalne
programowanie strukturalne programowanie strukturalne charakteryzuje się użyciem prostych, ściśle zdefiniowanych struktur (konstrukcji programistycznych) sekwencja instrukcja warunkowa iteracja wywołanie podprogramu w programowaniu strukturalnym unikamy instrukcji skoku oraz innych instrukcji zakłócających sekwencyjne wykonanie programu (break, continue, switch)
programowanie obiektowe program jest zbiorem obiektów, które komunikują się ze sobą za pomocą przesyłanych komunikatów obiekt to byt zawierający dane i posiadający zdolność do wykonywania operacji na danych cechy obiektów dziedziczenie polimorfizm hermetyczność enkapsulacja
programowanie logiczne program składa się ze zbioru faktów, zbioru przesłanek i celu wnioskowania wykonanie programu to próba udowodnienia celu w oparciu o znane fakty i podane przesłanki obliczenia wykonywane są "przy okazji" dowodzenia celu program nie specyfikuje sposobu dojścia do celu, lecz cel
przykład programowania logicznego znane fakty Jan jest ojcem Jerzego, Jerzy jest ojcem Janusza i Józefa bycie dziadkiem oznacza bycie ojcem ojca cel wnioskowania kto jest dziadkiem Janusza? ojciec(jan,jerzy). ojciec(jerzy,janusz). ojciec(jerzy,józef). dziadek(x,z) :- ojciec(x,y), ojciec(y,z).?- dziadek(x,janusz).
pozostałe paradygmaty programowania programowanie sekwencyjne i współbieżne programowanie współbieżne synchroniczne asynchroniczne programowanie współbieżne scentralizowane rozproszone programowanie skalarne i wektorowe lub macierzowe programowanie zdarzeniowe programowanie aspektowe