Laboratorium przedmiotu „Paradygmaty Programowania”

Transkrypt

Laboratorium przedmiotu „Paradygmaty Programowania”
Laboratorium przedmiotu
„Paradygmaty Programowania”
Laboratorium 6
Podstawy programowania w języku Scheme i środowisko
DrScheme.
1. Wprowadzenie
Język Scheme należy do rodziny funkcyjnych języków programowania. Został stworzony w latach
70 jako uproszczenie i ulepszenia języka Lisp.
Jako język programowania ogólnego
przeznaczenia, Scheme pozwala na tworzenie bardzo szerokiego spektrum aplikacji.
DrScheme jest środowiskiem programistycznym umożliwiającym tworzenie aplikacji w wielu
odmianach języka Scheme. Środowisko to można bezpłatnie pobrać ze strony internetowej
projektu http://www.plt-scheme.org/.
Informacje dotyczące tej części przedmiotu można też odnaleźć w następującej literaturze:
•
•
•
M. Felleisen, R. B. Findler, M. Flatt, S. Krishnamurthi „Projektowanie oprogramowania.
Wstęp do programowania i techniki komputerowej“, Helion, 2003.
M. Felleisen, R. B. Findler, M. Flatt, S. Krishnamurthi „How to Design Programs. An
Introduction to Computing and Programming”, online: http://www.htdp.org/2003-0926/Book/. (oryginalna wersja poprzedniej pozycji).
R. Kent Dybvig, „The Scheme Programming Language. Third Edition”, online:
http://www.scheme.com/tspl3/.
2. Środowisko DrScheme
2. 1 Rozpoczęcie pracy z środowiskiem DrScheme.
Po uruchomieniu środowiska pojawia się okno główne programu (przedstawione na rys. 1),
które składa się z czterech głównych elementów: paska narzędziowego, okna definicji, okna
interakcji oraz paska statusu.
Paradygmaty programowania
2
Rysunek 1 Okno główne programu DrScheme
Środowisko DrScheme obsługuje wiele wersji języka Scheme różniące się stopniem
zaawansowania użytkownika. W celu wybrania odpowiedniej – dla danych zajęć – wersji
języka, należy z menu „Language” wybrać opcję „Choose language” co spowoduje
wyświetlenie się następującego okna dialogowego:
Rysunek 2 Okno wyboru języka
Paradygmaty programowania
3
Na początku każdych zajęć należy wybrać odpowiednią wersję języka podaną w instrukcji.
UWAGA!! W przypadku pierwszego uruchomienia środowiska wybranie języka, z którego
chce się korzystać jest obligatoryjne.
2.1.1 Okno definicji
Okno definicji służy jako edytor do definiowania programu w języku Scheme. Na rysunku 1
przedstawiony został przykładowy program służący do obliczania wartości funkcji silnia1:
Przykład 1 – przykładowa funkcja w języku Scheme:
;;funkcja silnia: liczba->liczba
(define (silnia n)
(if (zero? n)
1
(* n (silnia (- n 1)))))
W
języku Scheme nawiasy są wszechobecne w bardzo dużej liczbie, dlatego
programowanie wymaga szczególnej uwagi. Na szczęście edytor DrScheme posiada funkcje
zarządzania nawiasami. Przede wszystkim bardzo przydatną funkcją jest zmiana koloru tła
pomiędzy odpowiadającymi sobie nawiasami w przypadku gdy kursor znajduje się koło
jednego z nich.
Rysunek 3 Przykładowy program w oknie definicji
W przypadku przejścia do nowej linii edytor dokonuje automatycznych wcięć w kodzie
programu. Należy pamiętać jednak, że funkcja ta ma charakter czysto estetyczny, gdyż
podobnie jak w innych popularnych językach programowania tj. C++, Pascal czy Java
również w przypadku Scheme białe znaki nie mają znaczenia.
2.1.2 Okno interakcji
Okno interakcji pozwala na wprowadzanie wyrażeń języka Scheme w celu ich
natychmiastowego wykonania. Po wprowadzeniu i zatwierdzeniu wyrażenia DrScheme
1
Program ten przedstawia również sposób zapisywania komentarzy, które w języku Scheme poprzedza się
podwójnym znakiem ‘;’.
Paradygmaty programowania
4
wykona je i wyświetli wynik lub komunikat o błędzie. Następnie w oknie interakcji pojawi
się kolejny znak zachęty „>” i system będzie oczekiwał na kolejne wyrażenie.
W przypadku gdy wprowadzone wyrażenie nie jest kompletne, lecz użytkownik naciśnie
Enter DrScheme rozpocznie nową linię i będzie oczekiwał na wprowadzenie dalszej części
wyrażenia.
Poprzednio wprowadzone wyrażenie można skopiować do bieżącej linii wciskając kolejno
ESC i p.
2.2 Analizator składni
Ciekawą opcją środowiska jest analizator składni. Przedstawia ona – w sposób graficzny –
relacje pomiędzy funkcjami i zmiennymi w programie wpisanym w oknie definicji.
Podstawowym mechanizmem oferowanym przez analizator składni jest jej kolorowanie.
Ponadto najeżdżając kursorem myszy na jakikolwiek symbol wprowadzony przez
użytkownika pokazuje miejsce, w którym ten symbol został zdefiniowany. Z kolei, gdy
użytkownik najedzie kursorem myszy na definicję symbolu (jego pierwsze wystąpienie w
programie) analizator pokaże wszystkie jego wystąpienia w programie (rys. 3)
Rysunek 4 Okno Analizatora składni
Dodatkowo klikając prawym przyciskiem myszy nad jednym z symboli, wyświetla się menu
kontekstowe:
Paradygmaty programowania
5
Rysunek 5 Menu kontekstowe w analizatorze składni
Ciekawą opcją jest „Rename …” pozwalającą na zmianę nazwy symbolu w całym wyrażeniu.
2.3 Okno Debug
Kolejną opcją oferowaną przez środowisko DrScheme jest debugowanie programu,
pozwalające na wykonywanie jego kodu krok po kroku. Okno debug, przedstawione na rys.4
otwiera się klikając przycisk:
Rysunek 6 Okno debugowania
Podzielone jest ono na 4 okna: definicji, interakcji stosu i zmiennych. Okno definicji w tym
przypadku jest oknem tylko do odczytu. Zielona strzałka jaka się w nim pojawia przedstawia
obecny punkt wykonania programu. Dodatkowo pozwala ono na ustawianie tzw.
„breakpoint -ów” , czyli punktów, w których ma się zatrzymać wykonywanie programu.
Breakpointy ustawiane są przez kliknięcie na kodzie programu prawym przyciskiem myszy i
wybranie z menu kontekstowego opcji „Pause at this point”.
Okna stosu i zmiennych służą do przedstawiania odpowiednio: jakie instrukcje obecnie
znajdują się na stosie oraz jaka jest obecna wartość zmiennych.
Przyciski jakie pojawiły się na pasku znajdującym się nad oknem definicji oznaczają
odpowiednio:
Paradygmaty programowania
6
Wstrzymanie wykonywania polecenia
Wykonanie programu do końca
Obliczenie wartości następnego wyrażenia w programie
Obliczenie następnego wyrażenia bez zagłębiania się w wyrażenia
wewnętrzne
Wykonanie obecnej funkcji do końca
UWAGA!!! Opcja debugowania programu nie jest dostępna w następujących wersjach języka:
How to Design Programs
Beginning Student
Beginning Student with List Abbreviations
Itermediate Student
Intermediate Student with lambda
2.4
Stepper
Kolejną ciekawą cechą środowiska DrScheme jest Stepper. Pozwala on na wizualną analizę
procesu obliczania wartości wyrażenia.
Rysunek 7 Okno steppera w środowisku DrScheme
Paradygmaty programowania
7
UWAGA!!! Opcja Steppera jest dostępna tylko w następujących wersjach języka:
How to Design Programs
Beginning Student
Beginning Student with List Abbreviations
Itermediate Student
Intermediate Student with lambda
3. Podstawy programowania w języku Scheme
3.1 Notacja prefixowa
W większości języków programowania wyrażenia zapisuje się zgodnie z notacją infixową, w
której operator występuje pomiędzy operandami np. 3+4, (23.5 – 7) / 4. Język
Scheme wykorzystuje nawiast oraz notację prefixową, w której operator występuje przed
operandami, czyli:
> (+ 3 4)
7
> (- (- 23.5 7) 4)
4.125
3.2 System typów języka Scheme
3.2.1 Typy numeryczne
•
•
•
•
Typ całkowity: 3, 0, -12
Typ ułamkowy: 1/3, -4/5
Typ zmiennoprzecinkowy: 0.3, -3.14
Typ liczb złożonych: 0.0+1.0i oznacza √−1
W języku Scheme typy numeryczne nie mają określonego z góry zakresu wartości, gdyż
język ten wykorzystuje tzw. arytmetykę dowolnej precyzji (arbitrary arithmetic). W praktyce
oznacza to, że dokładność obliczeń ograniczona jest tylko rozmiarem posiadanej pamięci.
Przykład 2 – wywołanie funkcji silnia zdefiniowanej w przykładzie 1:
> (silnia 1000)
4023872600770937735437024339230039857193748642107146325437999104299385123986290205920
4420848696940480047998861019719605863166687299480855890132382966994459099742450408707
3759918823627727188732519779505950995276120874975462497043601418278094646496291056393
8874378864873371191810458257836478499770124766328898359557354325131853239584630755574
0911426241747434934755342864657661166779739666882029120737914385371958824980812686783
8374559731746136085379534524221586593201928090878297308431392844403281231558611036976
8013573042161687476096758713483120254785893207671691324484262361314125087802080002616
8315102734182797770478463586817016436502415369139828126481021309276124489635992870511
4964975419909342221566832572080821333186116811553615836546984046708975602900950537616
4758477284218896796462449451607653534081989013854424879849599533191017233555566021394
5039973628075013783761530712776192684903435262520001588853514733161170210396817592151
Paradygmaty programowania
8
0907788019393178114194545257223865541461062892187960223838971476088506276862967146674
6975629112340824392081601537808898939645182632436716167621791689097799119037540312746
2228998800519544441428201218736174599264295658174662830295557029902432415318161721046
5832036786906117260158783520751516284225540265170483304226143974286933061690897968482
5901254583271682264580665267699586526822728070757813918581788896522081643483448259932
6604336766017699961283186078838615027946595513115655203609398818061213855860030143569
4527224206344631797460594682573103790084024432438465657245014402821885252470935190620
9290231364932734975655139587205596542287497740114133469627154228458623773875382304838
6568897646192738381490014076731044664025989949022222176590433990188601856652648506179
9702356193897017860040811889729918311021171229845901641921068884387121855646124960798
7229085192968193723886426148396573822911231250241866493531439701374285319266498753372
1894069428143411852015801412334482801505139969429015348307764456909907315243327828826
9864602789864321139083506217095002597389863554277196742822248757586765752344220207573
6305694988250879689281627538488633969099598262809561214509948717012445164612603790293
0912088908694202851064018215439945715680594187274899809425474217358240106367740459574
1785160829230135358081840096996372524230560855903700624271243416909004153690105933983
8357779394109700277534720000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000
3.2.2 Typ logiczny
Typ logiczny przyjmuje w języku Scheme dwie wartości: true lub false (w niektórych
implementacjach tego języka oznaczanych również symbolami, odpowiednio #t i #f.
Przykład 3 – typ logiczny:
>(integer? 4)
true
>(integer? 3.5)
false
>(integer? 1/3)
false
>(not true)
false
3.2.3 Typ znakowy
Dane znakowe w języku Scheme są reprezentowane poprzez dołączenie do znaku prefixu
#\, czyli: #\a oznacza znak a. Pewne znaki mają przypisane bardziej opisowe nazwy np.
#\newline, #\tab, #\space.
Przykład 4 – typ znakowy:
>(char? #\space)
true
>(char-upcase #\a)
#\A
>(char-downcase #\D)
#\d
Paradygmaty programowania
9
3.2.4 Łańcuchy znaków
Łańcuchy znaków definiuje się w języku Scheme jako sekwencję znaków umieszczoną
pomiędzy cudzysłowami. Łańcuchy znaków są w języku Scheme typem złożonym.
Przykład 5 – Łańcuchy znaków:
>”Scheme jest fajny”
”Scheme jest fajny”
>(string-append ”Scheme” ” jest” ” fajny”)
”Scheme jest fajny”
3.2.5 Symbole
Symbole służą do przedstawiania informacji symbolicznej. Ich zadaniem jest
reprezentowanie prostych danych jak imiona, polecenia, nagłówki. W przeciwieństwie do
łańcuchów znaków symbole są typem prostym. W języku Scheme symbole są ciągami
znaków poprzedzonymi pojedynczym apostrofem, lub funkcją quote (w symbolach nie
można stosować znaków spacji i przecinków).
Przykład 6 – Symbole
>’Witaj
’Witaj
>(quote Witaj)
’Witaj
3.3 Definiowanie funkcji w języku Scheme
Definiowanie funkcji w języku Scheme jest wyjątkowo proste. Wykorzystywane jest w tym
celu słowo kluczowe define, po którym występuje deklaracja funkcji (w nawiasach
występują nazwa funkcji, wymagane parametry) oraz jej ciało:
(define (nazwa_funkcji parametry)
(wyrazenie))
Przykład 7 – Definiowanie funkcji:
(define (razy2 x)
(* 2 x)
(define (dodaj x y)
(+ x y))
wywołanie funkcji (w oknie interakcji):
>(razy2 4)
8
>(dodaj 2 3)
5
Paradygmaty programowania
10
W środowisku DrScheme funkcje definiowane są w oknie definicji opisanym w punkcie
2.1.1. Aby możliwe było wykorzystanie zdefiniowanej wcześniej funkcji, środowisko
DrScheme
wymaga
kliknięcia
przycisku
na pasku narzędzi okna
głównego. W przypadku, gdy użytkownik chce wywołać funkcję bez uprzedniego kliknięcia
na ten przycisk wyświetlony zostanie komunikat:
3.4 Instrukcje warunkowe
3.4.1 Wyrażenie warunkowe
Warunkami będziemy nazywać wszystkie wyrażenia, które w wyniku zwracają wartość typu
logicznego. Język Scheme posiada wbudowanych szereg funkcji, które mogą być
wykorzystane jako warunki np. number?, string?, char?, odd?, even?, zero?,
not. Zaimplementowane w nim zostały również podstawowe operatory logiczne tj. =, <, >,
<=, >=. Dodatkowo wyrażenia warunkowe mogą być łączone za pomocą funkcji and i or:
Przykład 8 – Wyrażenia warunkowe
(define (CzyLiczbaJestWiekszaNiz10 x)
(and (number? x) (> x 10)))
>(CzyLiczbaJestWiekszaNiz10 3)
false
>(CzyLiczbaJestWiekszaNiz10 12)
true
3.4.2 Funkcja warunkowa if
Funkcja warunkowa if jest odpowiednikiem dobrze znanej, z innych języków
programowania, instrukcji warunkowej. Składnia jej przedstawia się następująco:
Paradygmaty programowania
11
(if wyrażenie_warunkowe
wyrażenie_prawda
wyrażenie_fałsz)
Wyrażenie_prawda jest obliczane w przypadku gdy wyrażenie_warunkowe zwróci
wartość true, w przeciwnym przypadku obliczane jest wyrażenie wyrażenie_fałsz.
Przykład 9 – Funkcja warunkowa if:
(define (powiekszDodatnieO2aUjemneO5 x)
(if (> x 0)
(+ x 2)
(+ x 5)))
>(powiekszDodatnieO2aUjemneO5 4)
9
>(powiekszDodatnieO2aUjemneO5 -4)
1
3.4.3 Funkcja warunkowa cond
Funkcja warunkowa cond upraszcza tworzenie zagnieżdżonych funkcji if.
Składnia tej funkcji przedstawia się następująco:
(cond (wyrażenie_warunkowe1 wyrażenie1)
(wyrażenie_warunkowe2 wyrażenie2)
(wyrażenie_warunkowe3 wyrażenie3)
...
(wyrażenie_warunkoweN wyrażenieN)
(else wyrażenie))
Wystąpienie funkcji else jest opcjonalne.
Przykład 10 – Funkcja warunkowa cond:
(define (sprawdz x)
(cond ((< x 0) ”liczba mniejsza od 0”)
((and (>= x 0) (<= x 10)) ”liczba z przedziału od 0 do 10”)
((> x 10) ”liczba większa od 10”)))
>(sprawdz -1)
”liczba mniejsza od 0”
>(sprawdz 5)
”liczba z przedziału od 0 do 10”
>(sprawdz 12)
”liczba większa od 10”
Paradygmaty programowania
12
3.5 Deklaracje zmiennych
Choć w językach czysto funkcyjnych zmienne, znane z języków imperatywnych nie istnieją,
w literaturze pojęcie to często stosowane jest w celu określenia etykiety dla wartości, której
po zdefiniowaniu nie można modyfikować2. W języku Scheme takie wartości definiujemy –
podobnie jak funkcje – za pomocą polecenia define, lecz w tym przypadku składnia jest
troszkę inna:
(define nazwa wyrazenie)
Przykład 11 – Deklarowanie zmiennych za pomocą polecenia define
(define DLUGOSC_BOKU 20)
(define POLE_POW (* DLUGOSC_BOKU DLUGOSC_BOKU))
Lokalne zmienne można też definiować wewnątrz funkcji za pomocą polecenia let.
(let ((nazwa1 wyrazenie1)
(nazwa2 wyrazenie2)
…
(nazwaN wyrazenieN))
(wyrazenie_ciala_funkcji))
Zmienne te są widoczne wyłącznie w wyrażeniu stanowiącym ciało polecenia let.
Przykład 12 – Deklarowanie zmiennych za pomocą polecenia let
(define (sumuj)
(let ((x 1)
(y 2))
(+ x y)))
polecenia let mogą być zagnieżdżone:
(define (sumuj)
(let ((x 1))
(let ((y 2))
(+ x y))))
2
Język Scheme nie jest językiem czysto funkcyjnym, dlatego zaimplementowana jest w nim konstrukcja
pozwalająca na modyfikację zdefiniowanych wartości, nie będziemy się nią jednak zajmować na zajęciach.
Paradygmaty programowania
13
4. Zadania do samodzielnego wykonania
1. W poniższych wyrażeniach uzupełnij nawiasy tak, aby były to poprawne wyrażenia języka
Scheme:
a. / / * * 1 2 3 4 5 6
b. * 1 – 2 * 3 4 + / 5 6 7
c. + * 1 2 - + * 3 4 / 5 6
Uwaga: może istnieć więcej niż jedno rozwiązanie
2. Przekształć poniższe wyrażenia z zapisu matematycznego lub infiksowego na zapis
prefiksowy
a. 33 +
∗ (23 −
()
b. (7*2 / 28) * (2/3)
c.
10)
+ (1 − 2) ∗ 15
Uwaga: do potęgowania służy funkcja expt
3. Funkcje trygonometryczne zaimplementowane w Scheme (sin, cos, tan) przyjmują
argument, który określa wartość kąta wyrażoną w radianach. Napisz funkcje zamieniającą
stopnie na radiany, a następnie nowe wersje funkcji trygonometrycznych (sinS, cosS,
tanS), w których argument określa wartość kąta wyrażoną w stopniach.
Uwaga: W funkcji zamieniającej stopnie na radiany należy zadeklarować zmienną pi i
przypisać jej wartość 3.14
4. Zdefiniować funkcję silnia z przykładu 1 i za jej pomocą obliczyć silnię z 2, 10, 100, 1000,
10000, 50000.
5. Napisz funkcję obliczającą sumę pierwszych n liczb naturalnych.
6. Napisz funkcje wyznaczającą wartość n-tego elementu ciągu Fibonacciego.
0
1
= + =0
= 1!
>1
7. (Zadanie dla osób chętnych i wytrwałych!) Obliczyć ręcznie silnie z 1000 i sprawdzić, czy
komputer się nie pomylił.

Podobne dokumenty