Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00630 007680 11066065 na godz. na dobę w sumie
Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowej - książka
Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowej - książka
Autor: , , , Liczba stron: 648
Wydawca: Helion Język publikacji: polski
ISBN: 83-7197-922-3 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> techniki programowania
Porównaj ceny (książka, ebook, audiobook).
Umiejętność programowania nie ma już charakteru czysto zawodowego. Księgowi muszą się posługiwać arkuszami kalkulacyjnymi i edytorami tekstu, fotografowie korzystają z edytorów zdjęć, muzycy programują syntezatory, zaś profesjonalni programiści tworzą skomplikowane aplikacje. Programowanie jest więc bardzo pożądaną umiejętnością, potrzebną nie tylko informatykom. Projektowanie oprogramowania wymaga takich samych zdolności analitycznych, jak matematyka. Jednak, w przeciwieństwie do matematyki, praca z programami jest aktywnym sposobem zdobywania wiedzy. Obcowanie z oprogramowaniem daje możliwość stałej interakcji, co pozwala na zgłębianie wiedzy, eksperymentowanie z nią oraz na stałą samoocenę.

Autorzy tej klasycznej publikacji stawiają tezę, iż 'każdy powinien nauczyć się, jak projektować oprogramowanie' i właśnie nauka podstaw projektowania jest jej tematem głównym. W książce znajdziesz wiele podstawowych algorytmów, wyjaśnienia takich pojęć, jak akumulacja wiedzy czy równość ekstensjonalna i intensjonalna, słowem wszystko to, co stanowi teoretyczną podstawę wiedzy programistycznej.

Poznasz między innymi: Z lektury książki 'Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowej' skorzystają zarówno studenci informatyki, jak też i słuchacze innych kierunków oraz wszystkie osoby, które chcą podbudować swoją wiedzę praktyczną solidnymi i przydatnymi podstawami teoretycznymi.
Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

IDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ SPIS TREĎCI SPIS TREĎCI KATALOG KSI¥¯EK KATALOG KSI¥¯EK KATALOG ONLINE KATALOG ONLINE ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG TWÓJ KOSZYK TWÓJ KOSZYK DODAJ DO KOSZYKA DODAJ DO KOSZYKA CENNIK I INFORMACJE CENNIK I INFORMACJE ZAMÓW INFORMACJE ZAMÓW INFORMACJE O NOWOĎCIACH O NOWOĎCIACH ZAMÓW CENNIK ZAMÓW CENNIK CZYTELNIA CZYTELNIA FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE Wydawnictwo Helion ul. Chopina 6 44-100 Gliwice tel. (32)230-98-63 e-mail: helion@helion.pl Projektowanie oprogramowania. Wstêp do programowania i techniki komputerowej Autorzy: Matthias Felleisen, Robert Bruce Findler, Matthew Flatt, Shriram Krishnamurthi T³umaczenie: Bartosz Grabski, Miko³aj Szczepaniak ISBN: 83-7197-922-3 Tytu³ orygina³u: How to Design Programs Format: B5, stron: 644 Przyk³ady na ftp: 32 kB Umiejêtnoġæ programowania nie ma ju¿ charakteru czysto zawodowego. Ksiêgowi musz¹ siê pos³ugiwaæ arkuszami kalkulacyjnymi i edytorami tekstu, fotografowie korzystaj¹ z edytorów zdjêæ, muzycy programuj¹ syntezatory, zaġ profesjonalni programiġci tworz¹ skomplikowane aplikacje. Programowanie jest wiêc bardzo po¿¹dan¹ umiejêtnoġci¹, potrzebn¹ nie tylko informatykom. Projektowanie oprogramowania wymaga takich samych zdolnoġci analitycznych, jak matematyka. Jednak, w przeciwieñstwie do matematyki, praca z programami jest aktywnym sposobem zdobywania wiedzy. Obcowanie z oprogramowaniem daje mo¿liwoġæ sta³ej interakcji, co pozwala na zg³êbianie wiedzy, eksperymentowanie z ni¹ oraz na sta³¹ samoocenê. Autorzy tej klasycznej publikacji stawiaj¹ tezê, i¿ „ka¿dy powinien nauczyæ siê, jak projektowaæ oprogramowanie” i w³aġnie nauka podstaw projektowania jest jej tematem g³ównym. W ksi¹¿ce znajdziesz wiele podstawowych algorytmów, wyjaġnienia takich pojêæ, jak akumulacja wiedzy czy równoġæ ekstensjonalna i intensjonalna, s³owem wszystko to, co stanowi teoretyczn¹ podstawê wiedzy programistycznej. Poznasz miêdzy innymi: • Podstawowe struktury, z których sk³adaj¹ siê programy komputerowe • Proste i z³o¿ony typy danych • Metody przetwarzania danych • Programowanie z u¿yciem rekurencji, algorytmy z nawracaniem • Projektowanie abstrakcyjne • Sposoby gromadzenia wiedzy • Wykorzystanie wektorów Z lektury ksi¹¿ki „Projektowanie oprogramowania. Wstêp do programowania i techniki komputerowej” skorzystaj¹ zarówno studenci informatyki, jak te¿ i s³uchacze innych kierunków oraz wszystkie osoby, które chc¹ podbudowaæ swoj¹ wiedzê praktyczn¹ solidnymi i przydatnymi podstawami teoretycznymi. Spis treści Przedmowa ..............................................................................................................9 Dlaczego każdy powinien uczyć się programować? ...................................................k................. 11 ............ 12 Metody projektowania...................................................k...................................................k..... Wybór Scheme i DrScheme...................................................k...................................................k.. ....... 14 ..................... 15 Podział książki...................................................k...................................................k.......... Podziękowania ...................................................k...................................................k............ .................. 18 Część I Przetwarzanie prostych typów danych 19 1. Studenci, nauczyciele i komputery...........................................................21 2. Liczby, wyrażenia i proste programy ......................................................23 ................ 23 Liczby i arytmetyka...................................................k...................................................k...... Zmienne i programy ...................................................k...................................................k....... ............. 26 Problemy ze zrozumieniem treści zadań...................................................k..................................... 29 ............................ 30 Błędy...............................................k...................................................k........................ Projektowanie programów...................................................k...................................................k.. ........ 33 3. Program składa się z funkcji i definicji zmiennych ..............................39 ................... 40 Składanie funkcji...................................................k...................................................k........ ............... 43 Definicje zmiennych ...................................................k...................................................k...... Proste ćwiczenia w tworzeniu funkcji...................................................k.......................................... 44 4. Instrukcje warunkowe i funkcje................................................................47 Wartości logiczne i relacje ...................................................k.............................................................. 47 Funkcje testujące warunki ...................................................k...................................................k........... 50 Warunki i funkcje warunkowe ...................................................k...................................................... 54 Projektowanie funkcji warunkowych...................................................k...........................................57 5. Informacje symboliczne..............................................................................63 Proste ćwiczenia z symbolami...................................................k....................................................... 65 6. Dane złożone. Część 1.: Struktury ............................................................69 Struktury ...................................................k...................................................k................ ........................ 69 Ćwiczenie rozszerzone: rysowanie prostych obrazów...................................................k................. 72 4 SPIS TREŚCI Definicje struktur ...................................................k...................................................k....... ................... 75 Definicje danych...................................................k...................................................k......... ................... 79 Projektowanie funkcji przetwarzających dane złożone ...................................................k................. 82 Rozszerzone ćwiczenie: przemieszczanie okręgów i prostokątów ............................................ 87 Rozszerzone ćwiczenie: gra w szubienicę ...................................................k................................... 91 7. Rodzaje danych............................................................................................95 Mieszanie i rozróżnianie danych ...................................................k.................................................. 95 Projektowanie funkcji przetwarzających dane mieszane...................................................k........ 100 Składanie funkcji — powtórka ...................................................k.................................................... 104 Rozszerzone ćwiczenie: przesuwanie figur...................................................k............................... 107 .......... 108 Błędne dane wejściowe ...................................................k...................................................k.... W1. Składnia i semantyka ................................................................................111 Słownictwo języka Scheme ...................................................k...................................................k. ...... 112 Gramatyka języka Scheme ...................................................k...................................................k.. ...... 112 Znaczenie w języku Scheme ...................................................k...................................................k..... 114 ..........................118 Błędy ...................................................k..... ...................................................k.............. ............. 121 Wyrażenia logiczne ...................................................k...................................................k....... Definicje zmiennych ...................................................k...................................................k...... ............. 122 ................. 124 Definicje struktur ...................................................k...................................................k....... Część II Przetwarzanie danych dowolnej wielkości 127 9. Dane złożone. Część 2.: Listy ..................................................................129 Listy .............................................k...................................................k......................... ............................129 Definicje danych dla list o dowolnej długości ...................................................k.......................... 133 Przetwarzanie list o dowolnej długości ...................................................k..................................... 135 Projektowanie funkcji dla rekursywnych definicji danych...................................................k..... 139 Więcej na temat przetwarzania prostych list ...................................................k............................ 142 10. Więcej na temat przetwarzania list.........................................................147 Funkcje zwracające listy...................................................k...................................................k. ............ 147 Listy zawierające struktury ...................................................k.......................................................... 152 Rozszerzone ćwiczenie: przemieszczanie obrazów ...................................................k................. 158 11. Liczby naturalne ........................................................................................161 Definiowanie liczb naturalnych...................................................k................................................... 161 Przetwarzanie liczb naturalnych dowolnej wielkości...................................................k.............. 163 Rozszerzone ćwiczenie: tworzenie list, testowanie funkcji...................................................k..... 166 Alternatywne definicje danych dla liczb naturalnych ...................................................k............... 168 Więcej o naturze liczb naturalnych...................................................k............................................. 173 12. Łączenie funkcji. Powtórka......................................................................177 Projektowanie skomplikowanych programów...................................................k......................... 177 Rekursywne funkcje zewnętrzne ...................................................k................................................ 178 Uogólnianie problemów i funkcji.......................k...................................................k...................... ... 183 Rozszerzone ćwiczenie: przestawianie słów ...................................................k............................. 187 W2. Skracanie list ..............................................................................................191 SPIS TREŚCI Część III Więcej o przetwarzaniu danych dowolnej wielkości 5 197 14. Więcej rekurencyjnych definicji danych ...............................................199 Struktury w strukturach ...................................................k...................................................k.. .......... 199 Rozszerzone ćwiczenie: drzewa poszukiwań binarnych ...................................................k........ 208 Listy w listach...................................................k...................................................k.......... .................... 212 Rozszerzone ćwiczenie: obliczanie wyrażeń języka Scheme...................................................k.. 215 15. Wzajemne odwołania w definicjach danych........................................217 Listy struktur. Listy w strukturach...................................................k............................................. 217 Projektowanie funkcji dla definicji danych zawierających wzajemne odwołania ................. 223 Rozszerzone ćwiczenie: więcej na stronach WWW................................................k..................... 225 16. Tworzenie programów metodą iteracyjnego ulepszania...................227 Analiza danych......................................k...................................................k........................ ................. 228 Definiowanie i ulepszanie klas danych...................................................k...................................... 229 Ulepszanie funkcji i programów ...................................................k................................................. 232 17. Przetwarzanie dwóch skomplikowanych elementów danych .........235 Jednoczesne przetwarzanie dwóch list. Przypadek 1. ...................................................k.............. 235 Jednoczesne przetwarzanie dwóch list. Przypadek 2. ...................................................k.............. 237 Jednoczesne przetwarzanie dwóch list. Przypadek 3. ...................................................k.............. 240 Upraszczanie funkcji ...................................................k...................................................k..... ............. 245 Projektowanie funkcji pobierających dwie złożone dane wejściowe ....................................... 247 Ćwiczenia z przetwarzania dwóch złożonych danych wejściowych....................................... 248 Rozszerzone ćwiczenie: obliczanie wyrażeń języka Scheme. Część 2. .................................... 251 Równość i testowanie...................................................k...................................................k..... ............ 253 W3. Lokalne definicje i zasięg leksykalny .....................................................261 Organizowanie programów za pomocą słowa local...................................................k................ 261 Zasięg leksykalny i struktura blokowa ...................................................k...................................... 276 Część IV Projektowanie abstrakcyjne 281 19. Podobieństwa w definicjach ....................................................................283 Podobieństwa w funkcjach...................................................k...................................................k. ....... 283 Podobieństwa w definicjach danych ...................................................k.......................................... 292 20. Funkcje są wartościami.............................................................................297 Składnia i semantyka ...................................................k...................................................k..... ............ 297 Kontrakty dla abstrakcyjnych i polimorficznych funkcji ...................................................k........ 299 21. Projektowanie funkcji abstrakcyjnych na podstawie przykładów...303 Abstrahowanie na podstawie przykładów...................................................k................................ 303 Ćwiczenia z abstrakcyjnymi funkcjami przetwarzającymi listy ............................................... 309 Abstrakcja i pojedynczy punkt kontroli...................................................k..................................... 311 Rozszerzone ćwiczenie: przemieszczanie obrazów jeszcze raz ................................................ 312 Uwaga: Projektowanie abstrakcji na podstawie szablonów...................................................k... 314 6 SPIS TREŚCI 22. Projektowanie abstrakcji ..........................................................................317 Funkcje zwracające funkcje ...................................................k.......................................................... 317 Projektowanie abstrakcji z funkcjami jako wartościami...................................................k.......... 319 Pierwsze spojrzenie na graficzny interfejs użytkownika ...................................................k........ 322 23. Przykłady matematyczne.........................................................................331 Ciągi i szeregi ...................................................k...................................................k.......... .................... 331 Ciągi i szeregi arytmetyczne...................................................k........................................................ 333 Ciągi i szeregi geometryczne ...................................................k....................................................... 334 Pole powierzchni pod wykresem funkcji...................................................k................................... 338 Nachylenie funkcji ...................................................k...................................................k....... ............... 340 W4. Bezpośrednie definiowanie funkcji ........................................................345 Część V Rekursja generatywna 351 25. Nowa postać rekursji ................................................................................353 Modelowanie kuli na stole ...................................................k...................................................k........ 354 Szybkie sortowanie...................................................k...................................................k....... .............. 357 26. Projektowanie algorytmów......................................................................363 Zakończenie...................................................k...................................................k.............. ................... 365 Rekursja strukturalna a generatywna................k...................................................k.........................368 Dokonywanie wyborów ...................................................k...................................................k...... ...... 369 27. Różne algorytmy rekurencyjne ...............................................................375 Fraktale ...................................................k...................................................k................. ........................ 375 Od plików do linii, od list do list list...................................................k.......................................... 380 Wyszukiwanie binarne ...................................................k...................................................k..... ......... 384 Metoda Newtona ...................................................k...................................................k........... ............. 390 Rozszerzone ćwiczenie: eliminacja Gaussa ...................................................k............................... 392 28. Algorytmy z nawracaniem ......................................................................397 Przechodzenie grafów...................................................k...................................................k..... ........... 397 Rozszerzone ćwiczenie: szachowanie hetmanów...................................................k..................... 403 W5. Koszt obliczeniowy oraz wektory ..........................................................405 Czas konkretny, czas abstrakcyjny ...................................................k............................................. 405 Definicja wyrażenia „rzędu”...................................................k........................................................ 410 Pierwsze spojrzenie na wektory...................................................k.................................................. 412 Część VI Gromadzenie wiedzy 423 30. Utrata wiedzy ............................................................................................425 Problem przetwarzania strukturalnego ...................................................k..................................... 425 Problem rekursji generatywnej...................................................k.................................................... 429 31. Projektowanie funkcji z akumulatorem................................................433 Czy akumulator jest potrzebny? ...................................................k................................................. 433 Funkcje z akumulatorem ...................................................k...................................................k... ........ 434 Przekształcanie funkcji na funkcje z akumulatorem...................................................k................ 436 SPIS TREŚCI 7 32. Dalsze użycie akumulacji.........................................................................447 Rozszerzone ćwiczenie: akumulatory i drzewa...................................................k........................ 447 Rozszerzone ćwiczenie: misjonarze i ludożercy...................................................k....................... 452 Rozszerzone ćwiczenie: plansza gry Solitaire...................................................k........................... 455 W6. Natura liczb niedokładnych ....................................................................457 Arytmetyka liczb o stałym rozmiarze ...................................................k........................................ 457 ................... 463 Przepełnienie ...................................................k...................................................k............ .................... 464 Niedomiar ...................................................k...................................................k................ Liczby w DrScheme...................................................k...................................................k........ ............ 465 Część VII Zmiana stanu zmiennych 467 34. Pamięć dla funkcji .....................................................................................469 35. Przypisanie do zmiennych.......................................................................475 Działanie prostych przypisań ...................................................k...................................................... 475 Sekwencja wyrażeń obliczeniowych...................................................k........................................... 477 Przypisania i funkcje ...................................................k...................................................k.... .............. 479 Pierwszy użyteczny przykład...................................................k...................................................... 482 36. Projektowanie funkcji z pamięcią ...........................................................485 Zapotrzebowanie na pamięć...................................................k...................................................k..... 485 Pamięć i zmienne stanu ...................................................k...................................................k... .......... 487 Funkcje inicjalizujące pamięć...................................................k....................................................... 489 Funkcje zmieniające pamięć...................................................k......................................................... 489 37. Przykłady zastosowania pamięci............................................................497 Inicjalizacja stanu ...................................................k...................................................k...... .................. 497 Zmiana stanu przez interakcję z użytkownikiem ...................................................k.................... 500 Zmiany stanu przez rekursję ...................................................k....................................................... 508 Ćwiczenia na zmianach stanu ...................................................k..................................................... 514 Rozszerzone ćwiczenie: zwiedzanie ...................................................k...........................................516 W7. Końcowa składnia i semantyka...............................................................519 Słownik Advanced Scheme...................................................k...................................................k.. ..... 519 Gramatyka Advanced Scheme ...................................................k...................................................k. 519 Znaczenie Advanced Scheme ...................................................k...................................................k... 522 Błędy w Advanced Scheme...................................................k...................................................k.. ..... 534 Część VIII Zmiana wartości złożonych 539 39. Hermetyzacja .............................................................................................541 Abstrahowanie ze zmiennymi stanu ...................................................k.......................................... 541 Ćwiczenia z hermetyzacji ...................................................k...................................................k. ......... 551 40. Mutacja struktur ........................................................................................553 Struktury z funkcji...................................................k...................................................k...... ................ 553 Mutacja struktur funkcjonalnych ...................................................k................................................ 556 8 SPIS TREŚCI Mutacja struktur...................................................k...................................................k......... ................. 558 Mutacja wektorów ...................................................k...................................................k......... ............. 565 Zmiana zmiennych, zmiana struktur ...................................................k......................................... 567 41. Projektowanie funkcji zmieniających struktury ..................................571 Po co mutować struktury ...................................................k...................................................k.. ........ 571 Zasady projektowania strukturalnego i mutacji, część 1. ...................................................k....... 572 Zasady projektowania strukturalnego i mutacji, część 2. ...................................................k....... 583 Ćwiczenie rozszerzone: ruchome obrazy po raz ostatni...................................................k......... 594 42. Równość......................................................................................................595 ......... 595 ........... 596 Równość ekstensjonalna ...................................................k...................................................k... Równość intensjonalna................................k...................................................k....................... 43. Zmiana struktur, wektorów i obiektów................................................601 Ćwiczenia praktyczne z wektorami...................................................k............................................601 .......... 616 Zbiory struktur z cyklami...........................k...................................................k........................ Nawracanie ze stanem ...................................................k...................................................k..... .......... 626 Zakończenie ...............................................................................................629 ........... 629 Technika obliczeniowa...................................................k...................................................k.... Programowanie ...................................................k...................................................k............ ............... 630 .................. 631 Krok naprzód........................................k...................................................k........................ Dodatki 633 Skorowidz...................................................................................................635 17 Przetwarzanie dwóch skomplikowanych elementów danych Czasami funkcja pobiera dwa argumenty należące do klas zdefiniowanych za pomocą skomplikowanych definicji danych. W niektórych przypadkach jeden z argumentów powinien być traktowany tak, jakby był argumentem atomowym; precyzyjnie sformu- łowany opis celu zazwyczaj to wyjaśnia. W innych przypadkach oba argumenty muszą być przetwarzane równolegle. Czasem funkcja będzie musiała brać pod uwagę wszystkie możliwe przypadki i odpowiednio przetwarzać dane argumenty. Ten rozdział ilustruje te trzy możliwości za pomocą przykładów i wprowadza rozszerzoną metodę projekto- wania dla ostatniego przypadku. W ostatnim podrozdziale omawiamy równoważność danych złożonych i jej związek z procesem testowania; ma to istotne znaczenie dla au- tomatyzacji testów funkcji. Jednoczesne przetwarzanie dwóch list. Przypadek 1. Przeanalizuj następujący kontrakt, opis celu i nagłówenk: ;; zastap-empty-lista : lista-liczb lista-liczb - lista-liczb ;; tworzy nową listę zastępując empty w liście dana-lista-liczb1 listą dana-lista-liczb2 (define (zastap-empty-lista dana-lista-liczb1 dana-lista-liclzb2) …) Kontrakt mówi, że funkcja pobiera dwie listy; z takim zdarzeniem nie spotkaliśmy się wcześniej. Zobaczmy, jak nasza metoda projektowania snprawdzi się w tym przypadku. Po pierwsze, tworzymy przykłady. Przypuśćmy, że pierwszą daną wejściową jest empty. Funkcja zastap-empty-lista powinna w takim przypadku zwrócić drugi argument, niezależnie od tego, co zawiera: (zastap-empty-lista empty L) = L W powyższym równaniu L reprezentuje dowolną listę liczb. Przypuśćmy teraz, że pierwszy argument jest różny od empty. Opis celu mówi, że powinniśmy w takim przy- padku zastąpić empty na końcu listy dana-lista-liczb1 listą dana-lista-liczb2: 236 17. PRZETWARZANIE DWÓCH SKOMPLIKOWANYCH ELEMENTÓW DANYCH (zastap-empty-lista (cons 1 empty) L) ;; oczekiwana wartość: (cons 1 L) (zastap-empty-lista (cons 2 (cons 1 empty)) L) ;; oczekiwana wartość: (cons 2 (cons 1 L)) (zastap-empty-lista (cons 2 (cons 11 (cons 1 empty))) L) ;; oczekiwana wartość: (cons 2 (cons 11 (cons 1 L))) W powyższych przykładach L ponownie reprezentuje dowolną listę liczb. Przykłady sugerują, że tak długo, jak drugi argument jest listą, nie ma znaczenia, co on zawiera; w przeciwnym przypadku nie miałoby sensu zastępowanie empty drugim argumentem. Oznacza to, że mając na uwadze pierwszy argument, powinniśmy wyko- rzystać szablon dla funkcji przetwarzających listy:n (define (zastap-empty-lista dana-lista-liczb1 dana-lista-liclzb2) (cond ((empty? dana-lista-liczb1) …) (else … (first dana-lista-liczb1) … (zastap-empty-lista (rest dana-lista-liczb1) dana-lista-liczb2) … ))) Drugi argument traktujemy na razie tak, jakby był danną atomową. Wypełnijmy teraz puste miejsca w szablonie zgodnie z zaleceniami metody projekto- wania. Jeśli lista dana-lista-liczb1 jest pusta, funkcja zastap-empty-lista zwraca dana-lista-liczb2 zgodnie z naszymi przykładami. W drugiej klauzuli wyrażenia cond, odpowiadającej danej na wejściu niepustej liście dana-lista-liczb1, musimy przeanalizować dostępne wyrażenia: (1) (first dana-lista-liczb1) wyciąga pierwszy element listy, (2) (zastap-empty-lista (rest dana-lista-liczb1) dana-lista-liczb2) zamienia empty na liście (rest dana-lista-liczb1) listą dana-lista-liczb2. Aby lepiej zrozumieć, co to oznacza, przeanalizuj ponniższy przykład: (zastap-empty-lista (cons 2 (cons 11 (cons 1 empty))) L) ;; oczekiwana wartość: (cons 2 (cons 11 (cons 1 L))) Powyżej (first dana-lista-liczb1) wynosi 2, (rest dana-lista-liczb1) ma wartość (cons 11 (cons 1 empty)), zaś (zastap-empty-lista (rest dana-lista-liczb1) dana-lista-liczb2) zwraca wartość (cons 11 (cons 1 dana-lista-liczb2)). Łącząc liczbę 2 z ostatnią wartością za pomocą in- strukcji cons, możemy otrzymać pożądany wynik. Ogólnnie: (cons (first dana-lista-liczb1) (zastap-empty-lista (rest dana-lista-liczb1) dana-lista- liczb2)) jest wynikiem drugiej klauzuli wyrażenia cond. Listing 17.1 zawiera kompletną definicję funkcji. JEDNOCZESNE PRZETWARZANIE DWÓCH LIST. PRZYPADEK 2. 237 Listing 17.1. Kompletna definicja funkcji zastap-empty-lista ;; zastap-empty-lista : lista-liczb lista-liczb - lista-liczb ;; tworzy nową listę zastępując empty w liście dana-lista-liczb1 listą dana-lista-liczb2 (define (zastap-empty-lista dana-lista-liczb1 dana-lista-liclzb2) (cond ((empty? dana-lista-liczb1) dana-lista-liczb2) (else (cons (first dana-lista-liczb1) (zastap-empty-lista (rest dana-lista-liczb1) dana-lista-liczb2))))) Ćwiczenia Ćwiczenie 17.1. W wielu ćwiczeniach używaliśmy operacji append języka Scheme, która pobiera trzy listy i zestawia ich elementy w jedną nlistę: (append (list a) (list b c) (list d e f)) ;; oczekiwana wartość: (list a b c d e f) Wykorzystaj funkcję zastap-empty-lista do zdefiniowania funkcji nasz-append, która powinna działać identycznie jak append udostępniany w języku Scheme. Ćwiczenie 17.2. Opracuj funkcję krzyzuj, która pobierze listę symboli oraz listę liczb i zwróci wszystkie możliwe pary symboli z liczbami. Przykład: (krzyzuj (a b c) (1 2)) ;; oczekiwana wartość: (list (list a 1) (list a 2) (list b 1) (list b 2) (list c 1) n(list c 2)) Jednoczesne przetwarzanie dwóch list. Przypadek 2. W rozdziale 10. opracowaliśmy funkcję godziny- wynagrodzenie obliczającą wynagro- dzenie pracowników na podstawie przepracowanych godzin. Funkcja pobierała listę liczb (przepracowanych przez pracowników godzin) i zwracała inną listę liczb (należ- nych wynagrodzeń). Dla uproszczenia założyliśmy, że wszyscy pracownicy mają taką samą stawkę godzinową. Nawet jednak małe firmy zatrudniają pracowników na zróż- nicowanych warunkach. Przeważnie księgowy firmy utrzymuje dwa zbiory informacji: stałą, która między innymi zawiera stawkę godzinową danego pracownika, oraz tym- czasową, w której zawarta jest informacja o liczbie przepracowanych w ostatnich mie- siącach godzin. Nowy, rozszerzony opis problemu oznacza, że funkcja powinna pobierać dwie listy. Aby uprościć sobie ten problem, załóżmy, że listy zawierają jedynie liczby: jedna — stawki godzinowe, druga — liczby przepracowanych godzin. Oto nasz kontrakt, opis celu i nagłówek: 238 17. PRZETWARZANIE DWÓCH SKOMPLIKOWANYCH ELEMENTÓW DANYCH ;; godziny- wynagrodzenia : lista-liczb lista-liczb - lista-liczb ;; konstruuje nową listę zawierającą iloczyny odpowiendnich ;; elementów list dana-lista-liczb1 i dana-lista-liczb2 ;; ZAŁOŻENIE: listy mają równą długość (define (godziny- wynagrodzenia dana-lista-liczb1 dana-lista-liczb2) …) Możemy traktować listę dana-lista-liczb1 jako listę stawek godzinowych, zaś dana-lista- liczb2 jako listę przepracowanych w ostatnim miesiącu godzin. Aby otrzymać listę wy- nagrodzeń, musimy przemnożyć odpowiednie liczby z obnu list. Spójrzmy na kilka przykładów: (godziny- wynagrodzenia empty empty) ;; oczekiwana wartość: empty (godziny- wynagrodzenia (cons 5.65 empty) (cons 40 empty)) ;; oczekiwana wartość: (cons 226.0 empty) (godziny- wynagrodzenia (cons 5.65 (cons 8.75 empty)) (cons 40.0 (cons 30.0 empty))) ;; oczekiwana wartość: (cons 226.0 (cons 262.5 empty)) We wszystkich trzech przykładach na wejściu funkcji podano pary list takich samych długości. Jak napisaliśmy w dodatku do opisu celu, funkcja zakłada, że dane spełniają ten warunek — i faktycznie, stosowanie funkcji z naruszenniem tego warunku nie ma sensu. Warunek dotyczący danych wejściowych można wyjaśnić podczas opracowywania szablonu. Konkretnie, warunek mówi, że (empty? dana-lista-liczb1) ma wartość true wtedy i tylko wtedy, gdy (empty? dana-lista-liczb2) ma wartość true. Co więcej, (cons? dana-lista- liczb1) ma wartość true wtedy i tylko wtedy, gdy (cons? dana-lista-liczb2) ma wartość true. Innymi słowy, warunek upraszcza projekt struktury wyrażeń warunkowych cond w sza- blonie, ponieważ oznacza, że szablon jest podobny do szablonu dla funkcji przetwarza- jących listy: (define (godziny- wynagrodzenia dana-lista-liczb1 dana-lista-liczb2) (cond ((empty? dana-lista-liczb1) …) (else … ))) W pierwszej klauzuli cond zarówno dana-lista-liczb1 jak i dana-lista-liczb2 są listami pustymi — empty. Nie potrzebujemy więc żadnego selektora. W drugiej klauzuli za- równo dana-lista-liczb1 jak i dana-lista-liczb2 są skonstruowanymi listami, co oznacza, że potrzebujemy czterech selektorów: (define (godziny- wynagrodzenia dana-lista-liczb1 dana-lista-liczb2) (cond ((empty? dana-lista-liczb1) …) JEDNOCZESNE PRZETWARZANIE DWÓCH LIST. PRZYPADEK 2. 239 (else … (first dana-lista-liczb1) … (first dana-lista-liczb2) … … (rest dana-lista-liczb1) … (rest dana-lista-liczb2) … ))) Ponieważ ostatnie dwa selektory dotyczą list o identycznych długościach, w oczywisty sposób możemy je wykorzystać w naturalnej rekursji nfunkcji godziny- wynagrodzenia: (define (godziny- wynagrodzenia dana-lista-liczb1 dana-lista-liczb2) (cond ((empty? dana-lista-liczb1) …) (else … (first dana-lista-liczb1) … (first dana-lista-liczb2) … … (godziny- wynagrodzenia (rest dana-lista-liczb1) (rest dana-lista-liczb2)) … ))) Jedynym niezwykłym elementem tego szablonu jest rekursywne wywołanie funkcji zło- żone z dwóch wyrażeń, z których oba są selektorami dwóch argumentów funkcji. Jak się już przekonaliśmy, idea działania funkcji jest łatwa do wytłumaczenia dzięki założeniu, że dana-lista-liczb1 i dana-lista-liczb2 mają równą długość. Podczas definiowania funkcji będziemy postępować zgodnie z zaleceniami metody projektowania. Pierwszy przykład oznacza, że odpowiedzią pierwszej klauzuli wyraże- nia cond powinna być lista pusta — empty. W drugiej klauzuli mamy do dyspozycji trzy wartości: (1) (first dana-lista-liczb1), która reprezentuje pierwszy element listy stawek godzino- wych; (2) (first dana-lista-liczb2), która reprezentuje pierwszy element listy przepracowanych godzin; oraz (3) (godziny- wynagrodzenia (rest dana-lista-liczb1) (rest dana-lista-liczb2)), która jest listą wynagrodzeń dla reszt list dana-lista-liczb1 i dana-lista-liczb2. Aby otrzymać ostateczny wynik, musimy jedynie odpowiednio połączyć te wartości. A dokładniej, zgodnie z opisem celu musimy obliczyć wynagrodzenie dla pierwszego pra- cownika i skonstruować listę złożoną z tej wartości i wynagrodzeń pozostałych pracow- ników. Oznacza to, że odpowiedź dla drugiej klauzuli wyrażenia cond powinna wyglą- dać następująco: (cons (wynagrodzenie (first dana-lista-liczb1) (first dana-lista-liczb2)) (godziny- wynagrodzenia (rest dana-lista-liczb1) (rest dana-lista-liczb2))) Zewnętrzna funkcja wynagrodzenie pobiera dwa pierwsze elementy i oblicza odpowied- nie wynagrodzenie. Listing 17.2 zawiera kompletne definnicje obu funkcji. Listing 17.2. Kompletna definicja funkcji godziny- wynagrodzenia ;; godziny- wynagrodzenia : lista-liczb lista-liczb - lista-liczb ;; konstruuje nową listę zawierającą iloczyny odpowiendnich ;; elementów list dana-lista-liczb1 i dana-lista-liczb2 ;; ZAŁOŻENIE: listy mają równą długość 240 17. PRZETWARZANIE DWÓCH SKOMPLIKOWANYCH ELEMENTÓW DANYCH (define (godziny- wynagrodzenia dana-lista-liczb1 dana-lista-liczb2) (cond ((empty? dana-lista-liczb1) empty) (else (cons (wynagrodzenie (first dana-lista-liczb1) (first dana-lista-liczb2)) (godziny- wynagrodzenia (rest dana-lista-liczb1) (rest dana-lista-liczb2)))))) ;; wynagrodzenie : liczba liczba - liczba ;; oblicza wynagrodzenie na podstawie danych liczb: stawka-godzinowa oraz przepracowane-godziny (define (wynagrodzenie stawka-godzinowa przepracowane-godzinly) (∗ stawka-godzinowa przepracowane-godziny)) Ćwiczenia Ćwiczenie 17.3. W rzeczywistym świecie funkcja godziny- wynagrodzenia pobierałaby li- stę struktur reprezentujących pracowników i listę struktur reprezentujących przebieg prac w ostatnim miesiącu. Struktura pracownika zawiera jego nazwisko, numer PESEL oraz stawkę godzinową. Struktura opisująca przebieg pracy zawiera nazwisko pracow- nika i liczbę przepracowanych w danym miesiącu godzin. Wynikiem jest lista struktur zawierających nazwisko pracownika i należne mu wynangrodzenie. Zmodyfikuj funkcję z listingu 17.2 tak, aby pracowała na powyższych klasach da- nych. Opracuj potrzebne definicje struktur i definicje danych. Zastosuj metodę projek- towania w procesie modyfikacji funkcji. Ćwiczenie 17.4. Opracuj funkcję zepnij, która pobierze listę nazwisk oraz listę numerów telefonicznych i połączy je w listę podobną do książki telefonicznej. Zakładając, że ma- my następującą definicję struktury: (define-struct wpis (nazwisko numer)) pojedynczy wpis w książce telefonicznej konstruujemy za pomocą instrukcji (make-wpis s n), gdzie s jest symbolem, a n jest liczbą. Załóż, że dane na wejściu listy mają identyczne długości. Uprość definicję na tyle, na ile będzie to możnliwe. Jednoczesne przetwarzanie dwóch list. Przypadek 3. Oto trzeci opis problemu przedstawiony w formie konntraktu, opisu celu i nagłówka: ;; wybierz-z-listy : lista-symboli N[ = 1] - symbol ;; określa n-ty symbol na liście dana-lista-symboli, licząc od 1; ;; sygnalizuje błąd, jeśli na danej liście nie ma n-tegon symbolu (define (wybierz-z-listy dana-lista-symboli n) …) JEDNOCZESNE PRZETWARZANIE DWÓCH LIST. PRZYPADEK 3. 241 Powyższy program wymaga opracowania funkcji, która będzie pobierać liczbę naturalną i listę symboli. Obie dane wejściowe należą do klas opisanych skomplikowanymi defini- cjami danych, jednak inaczej niż w dwóch poprzednich problemach, klasy te są całkowi- cie rozłączne. Na listingu 17.3 przypominamy obie definnicje. Listing 17.3. Definicje danych dla funkcji wybierz-z-listy Definicje danych: liczba naturalna [ =1] (N[ =1]) jest albo: (1) 1, albo (2) (dodaj1 n), jeśli n należy do N[ =1]. lista-symboli jest albo: (1) listą pustą, empty, albo (2) (cons s ls), gdzie s jest symbolem, a ls jest listą synmboli. Ponieważ problem jest nietypowy, powinniśmy upewnić się, że nasze przykłady obejmują wszystkie ważne przypadki. Ten cel osiągamy zazwyczaj wybierając po jed- nym przykładzie dla każdej klauzuli z definicji i wybierając losowo elementy dla pozo- stałych, prostych elementów danych. W tym przykładzie taka procedura prowadzi nas do wybrania co najmniej dwóch elementów dla danej lista-symboli i dwóch dla N[ = 1]. Wybierzmy empty i (cons a empty) dla listy, oraz 1 i 3 dla liczb naturalnych. Po dwa przykłady dla obu argumentów oznaczają, że będziemy mieli ich łącznie cztery, nie mamy jednak danego wprost związku pomiędzy tymi dwoma argumentami, ani żadnych ogra- niczeń wspomnianych w kontrakcie: (wybierz-z-listy empty 1) ;; oczekiwane zachowanie: (error wybierz-z-listy … ) (wybierz-z-listy (cons a empty) 1) ;; oczekiwana wartość: a (wybierz-z-listy empty 3) ;; oczekiwane zachowanie: (error wybierz-z-listy … ) (wybierz-z-listy (cons a empty) 3) ;; oczekiwane zachowanie: (error wybierz-z-listy … ) Tylko jeden z czterech wyników jest symbolem; w pozostałych przypadkach otrzymali- śmy błędy związane z brakiem elementów na danych listnach. 242 17. PRZETWARZANIE DWÓCH SKOMPLIKOWANYCH ELEMENTÓW DANYCH Dyskusja o przykładach wykazała, że istnieją faktycznie cztery możliwe, niezależne przypadki, które musimy brać pod uwagę podczas projektowania funkcji. Możemy ana- lizować te przypadki za pomocą tabeli zawierającej nniezbędne warunki: (empty? dana-lista-symboli) (cons? dana-lista-symboli) (= n 1) ( n 1) Wiersze tabeli opisują dane wejściowe, dla których funkcja wybierz-z-listy musi określić, co podano jako listę symboli; w kolumnach rozróżniamy dane liczby naturalne. Co wię- cej, w tabeli mamy cztery pola, z których każde reprezentuje przypadek, w którym za- równo warunek odpowiedniej kolumny jak i wiersza ma wartość true. Możemy to wy- razić za pomocą wyrażeń z operatorem and w odpowiednich komórkach tabeli: (empty? dana-lista-symboli) (cons? dana-lista-symboli) (= n 1) ( n 1) (and (= n 1) (empty? dana-lista-symboli)) (and ( n 1) (empty? dana-lista-symboli)) (and (= n 1) (cons? dana-lista-symboli)) (and ( n 1) (cons? dana-lista-symboli)) Łatwo teraz wykazać, że dla dowolnej danej pary argumentów dokładnie jeden z czte- rech warunków zawartych w komórkach tabeli powyżej ni ma wartość true. Korzystając z naszej analizy przypadków, możemy teraz zaprojektować pierwszą część szablonu — wyrażenie warunkowe: (define (wybierz-z-listy dana-lista-symboli n) (cond [(and (= n 1) (empty? dana-lista-symboli)) …] [(and ( n 1) (empty? dana-lista-symboli)) …] [(and (= n 1) (cons? dana-lista-symboli)) …] [(and ( n 1) (cons? dana-lista-symboli)) …])) Wyrażenie cond sprawdza wszystkie cztery warunki wyróżniając wszystkie możliwości. Następnie, jeśli to możliwe, musimy dodać selektory don każdej klauzuli tego wyrażenia: (define (wybierz-z-listy dana-lista-symboli n) (cond [(and (= n 1) (empty? dana-lista-symboli)) …] [(and ( n 1) (empty? dana-lista-symboli)) … (odejmij1 n) …] [(and (= n 1) (cons? dana-lista-symboli)) … (first dana-lista-symboli) … (rest dana-lista-symboli)…] [(and ( n 1) (cons? dana-lista-symboli)) … (odejmij1 n) … (first dana-lista-symboli) … (rest dana-lista-symboli) …])) JEDNOCZESNE PRZETWARZANIE DWÓCH LIST. PRZYPADEK 3. 243 Dla liczby naturalnej n szablon zawiera co najwyżej jeden selektor, który określa po- przednika tej liczby w zbiorze liczb naturalnych. Dla listy dana-lista-symboli możliwe są maksymalnie dwa selektory. Jednak w przypadku, w którym prawdziwy jest warunek (= n 1) lub (empty? dana-lista-symboli), czyli jeden z dwóch argumentów jest atomowy, nie ma potrzeby stosowania odpowiadających tym danym wejściowym selektorów. Ostatni krok w procesie konstruowania szablonu wymaga wypisania szablonu z za- znaczonymi rekursjami dla wyrażeń, w których wyrażenia selektorów zwracają dane na- leżące do tej samej klasy, co dane wejściowe. W szablonie dla funkcji wybierz-z-listy takie działanie ma sens jedynie dla ostatniej klauzuli cond, która zawiera wyrażenia zarówno dla N[ = 1], jak i dla listy–symboli. Wszystkie inne klauzule zawierają co najwyżej jedno odpowiednie wyrażenie. Nie jest jednak do końca jasne, jak sformułować w tym przy- padku naturalną rekursję. Jeśli zbagatelizujemy cel funkcji i w kroku konstruowania sza- blonu wypiszemy wszystkie możliwe rekursje, otrzymamy trzy przypadki: (wybierz-z-listy (rest dana-lista-symboli) (odejmij1 n)) (wybierz-z-listy dana-lista-symboli (odejmij1 n)) (wybierz-z-listy (rest dana-lista-symboli) n) Ponieważ nie wiemy, ani która rekursja ma w tym przykładzie zastosowanie, ani czy możemy wykorzystać wszystkie trzy rekursje, przechondzimy do następnego etapu. Zgodnie z metodą projektowania, przeanalizujmy każdą z klauzul wyrażenia cond naszego szablonu i znajdźmy prawidłową odpowiedź na pnowyższe pytanie: (1) Jeśli warunek (and (= n 1) (empty? dana-lista-symboli)) jest prawdziwy, funkcja wy- bierz-z-listy powinna wybrać pierwszy element z pustej listy, co jest niemożliwe. Odpowiedzią funkcji będzie więc sygnalizacja o błędzien. (2) Jeśli warunek (and ( n 1) (empty? dana-lista-symboli)) jest prawdziwy, funkcja wy- bierz-z-listy powinna znowu wybrać element z pustej listy. Odpowiedzią jest więc znowu błąd. (3) Jeśli warunek (and (= n 1) (cons? dana-lista-symboli)) jest prawdziwy, funkcja wy- bierz-z-listy powinna zwrócić pierwszy element danej listy. Selektor (first dana- lista-symboli) przypomina nam, jak uzyskać ten element. Właśnie on będzie odpo- wiedzią funkcji. (4) W ostatniej klauzuli, jeśli warunek (and ( n 1) (cons? dana-lista-symboli)) jest praw- dziwy, musimy przeanalizować, co zwracają poszczególne selektory: (a) (first dana-lista-symboli) wybiera pierwszy element z listy symboli; (b) (rest dana-lista-symboli) reprezentuje resztę listy; oraz (c) (odejmij1 n) zwraca liczbę mniejszą od jeden od danego indeksu nlisty. Rozważmy przykład ilustrujący znaczenie powyższych wyrażeń. Przypuśćmy, że funkcję wybierz-z-listy zastosowano dla listy (cons a (cons b empty)) i licznby 2: (wybierz-z-listy (cons a (cons b empty)) 2) Funkcja powinna zwrócić symbol b, ponieważ (first dana-lista-symboli) zwróci a, natomiast (odejmij1 n) zwróci 1. Poniżej przedstawiamy efekty ewentualnego zasto- sowania trzech naturalnych rekursji dla tych wartośnci: 244 17. PRZETWARZANIE DWÓCH SKOMPLIKOWANYCH ELEMENTÓW DANYCH (a) (wybierz-z-listy (cons b empty) 1) zwraca b, czyli pożądaną wartość; (b) (wybierz-z-listy (cons a (cons b empty)) 1) zwraca wartość a, która jest sym- bolem, ale nie jest oczekiwaną wartością dla naszegon problemu; (c) (wybierz-z-listy (cons b empty) 2) sygnalizuje błąd, ponieważ indeks jest więk- szy niż długość listy. Powyższa analiza sugeruje, że powinniśmy użyć wyrażenia (wybierz-z-listy (cons b empty) 1) jako odpowiedzi ostatniej klauzuli cond. Oparte na przykładzie rozwią- zania są jednak często zawodne, powinniśmy więc spróbować zrozumieć, dlaczego to wyrażenie jest odpowiednie dla naszej funkcji. Przypomnij sobie, że zgodnie z opisem celu, (wybierz-z-listy (rest dana-lista-symboli) (odejmij1 n)) wybiera element o indeksie (n-1) z listy (rest dana-lista-liczb). Innymi słowy, zmniejszamy indeks o 1, skracamy listę o jeden element i szukamy w nowej liście elementu o zmniej- szonym indeksie. Wyrażenie zwraca wartość zgodną z oczekiwaniami, podobnie jak odpowiedź klauzuli z warunkiem (= n 1), przy założeniu, że dana-lista-symboli i n są wartościami złożonymi. Nasz wybór odpowiedzi dla ostatniej klauzuli jest więc całko- wicie uzasadniony. Kompletną definicję funkcji wybierz-z-listy przedstawia listing 17.4. Listing 17.4. Kompletna definicja funkcji wybierz-z-listy ;; wybierz-z-listy : lista-symboli N[ = 1] - symbol ;; określa n-ty symbol na liście dana-lista-symboli, licząc od 1; ;; sygnalizuje błąd, jeśli na danej liście nie ma n-tegon symbolu (define (wybierz-z-listy dana-lista-symboli n) (cond [(and (= n 1) (empty? dana-lista-symboli)) (error wybierz-z-listy lista jest za krótka )] [(and ( n 1) (empty? dana-lista-symboli)) (error wybierz-z-listy lista jest za krótka )] [(and (= n 1) (cons? dana-lista-symboli)) (first dana-lista-symboli)] [(and ( n 1) (cons? dana-lista-symboli)) (wybierz-z-listy (rest dana-lista-symboli) (odejmij1 n))])) Ćwiczenia Ćwiczenie 17.5. Opracuj funkcję wybierz-z-listy0, która wybierze elementy z listy podob- nie jak wybierz-z-listy, ale począwszy od indeksu 0. Przykłady: (symbol=? (wybierz-z-listy0 (list a b c d) 3) d) (wybierz-z-listy0 (list a b c d) 4) ;; oczekiwane zachowanie: (error wybierz-z-listy0 lista jest za krótka ) UPRASZCZANIE FUNKCJI 245 Upraszczanie funkcji Funkcja wybierz-z-listy zaprezentowana na listingu 17.4 jest bardziej skomplikowana niż jest to konieczne. Pierwsza i druga klauzula wyrażenia cond zwracają takie same odpo- wiedzi: błąd. Innymi słowy, jeśli wyrażenie: (and (= n 1) (empty? dana-lista-symboli)) lub (and ( n 1) (empty? dana-lista-symboli)) ma wartość true, efektem działania funkcji jest błąd. Możemy więc wykorzystać to po- dobieństwo i stworzyć prostsze wyrażenie cond: (define (wybierz-z-listy dana-lista-symboli n) (cond [(or (and (= n 1) (empty? dana-lista-symboli)) (and ( n 1) (empty? dana-lista-symboli))) (error wybierz-z-listy lista jest za krótka )] [(and (= n 1) (cons? dana-lista-symboli)) (first dana-lista-symboli)] [(and ( n 1) (cons? dana-lista-symboli)) (wybierz-z-listy (rest dana-lista-symboli) (odejmij1 n))])) Nowe wyrażenie jest prostym przełożeniem naszych obsnerwacji na język Scheme. Aby jeszcze bardziej uprościć naszą funkcję, musimy zapoznać się z regułą algebra- iczną dotyczącą wartości logicznych: (or (and warunek1 dany-warunek) (and warunek2 dany-warunek)) = (and (or warunek1 warunek2) dany-warunek) Powyższe równanie nazywa się prawem de Morgana. Zastosowanie go w naszej funkcji spowoduje następujące uproszczenie: (define (wybierz-z-listy n dana-lista-symboli) (cond [(and (or (= n 1) ( n 1)) (empty? dana-lista-symboli)) (error wybierz-z-listy lista jest za krótka )] [(and (= n 1) (cons? dana-lista-symboli)) (first dana-lista-symboli)] [(and ( n 1) (cons? dana-lista-symboli)) (wybierz-z-listy (rest dana-lista-symboli) (odejmij1 n))])) Rozważ teraz pierwszą część warunku (or (= n 1) ( n 1)). Ponieważ n należy do zbioru N[ = 1], warunek jest zawsze prawdziwy. Gdybyśmy jednak zastąpili go słowem true, otrzymalibyśmy warunek: 246 17. PRZETWARZANIE DWÓCH SKOMPLIKOWANYCH ELEMENTÓW DANYCH (and true (empty? dana-lista-symboli)) który jest równoważny z warunkiem (empty? dana-lista-symboli). Innymi słowy, funkcję możemy zapisać w następujący sposób: (define (wybierz-z-listy dana-lista-symboli n) (cond [(empty? dana-lista-symboli) (error wybierz-z-listy lista jest za krótka )] [(and (= n 1) (cons? dana-lista-symboli)) (first dana-lista-symboli)] [(and ( n 1) (cons? dana-lista-symboli)) (wybierz-z-listy (rest dana-lista-symboli) (odejmij1 n))])) Ta definicja jest znacznie prostsza niż ta, którą zandemonstrowaliśmy na listingu 17.4. Możemy uprościć naszą definicję jeszcze bardziej. Pierwszy warunek w ostatniej wersji funkcji wybierz-z-listy odrzuca wszystkie przypadki, w których dana-lista-symboli jest pusta. Wyrażenie (cons? dana-lista-symboli) w następnych dwóch klauzulach będzie więc miało zawsze wartość true. Jeśli zastąpimy warunek tą wartością i uprościmy wyra- żenie and, otrzymamy najprostszą z możliwych wersję funkcji wybierz-z-listy, którą przed- stawiliśmy na listingu 17.5. Mimo że ostatnia funkcja jest dużo prostsza od oryginalnej, ważne jest, byśmy rozumieli, że opracowaliśmy obie wernsje w sposób systematyczny i tylko dzięki temu możemy być pewni, że działają one poprawnie. Gdybyśmy próbowali od początku tworzyć wersję uproszczoną, prędzej czy późninej popełnilibyśmy błąd. Listing 17.5. Uproszczona definicja funkcji wybierz-z-listy ;; wybierz-z-listy : lista-symboli N[ = 1] - symbol ;; określa n-ty symbol na liście dana-lista-symboli, licząc od 1; ;; sygnalizuje błąd, jeśli na danej liście nie ma n-tego symbolu (define (wybierz-z-listy dana-lista-symboli n) (cond [(empty? dana-lista-symboli) (error wybierz-z-listy lista jest za krótka )] [(= n 1) (first dana-lista-symboli)] [( n 1) (wybierz-z-listy (rest dana-lista-symboli) (odejmij1 n))])) Ćwiczenia Ćwiczenie 17.6. Opracuj funkcję zastap-empty-lista zgodnie ze strategią z podrozdziału „Jednoczesne przetwarzanie dwóch list. Przypadek 2.”. Następnie systematycznie uprasz- czaj definicję funkcji. Ćwiczenie 17.7. Uprość definicję funkcji wybierz-z-listy0 z ćwiczenia 17.5 lub wyjaśnij, dlaczego nie można jej uprościć. PROJEKTOWANIE FUNKCJI POBIERAJĄCYCH DWIE ZŁOŻONE DANE WEJŚCIOWE 247 Projektowanie funkcji pobierających dwie złożone dane wejściowe Napotkamy czasem problemy, które wymagają funkcji pobierających dwie złożone klasy danych wejściowych. Najbardziej interesujące będą przypadki, w których obie dane będą miały nieznane rozmiary. Jak się przekonaliśmy w pierwszych trzech podrozdziałach, możemy postępować z takimi danymi wejściowymi na trzny różne sposoby. Odpowiednim podejściem do tego typu problemów jest postępowanie zgodne z za- leceniami metody projektowania. Przede wszystkim musimy przeprowadzić analizę da- nych i zdefiniować odpowiednie klasy danych. Następnie możemy stworzyć kontrakt, opis celu funkcji, które kolejno doprowadzają nas do momentu, w którym możemy przejść do następnego kroku. Zanim to jednak zrobimy, powinniśmy się zastanowić, z którą z na- stępujących sytuacji mamy do czynienia: (1) W niektórych przypadkach jeden z parametrów ma rolę dominującą. I odwrotnie, możemy traktować jeden z parametrów jako atomowy fragment danych z punktu widzenia opracowywanej funkcji. (2) W innych przypadkach oba parametry są zsynchronizowane. Muszą obejmować tę samą klasę wartości o takiej samej strukturze. Np. jeśli mamy dwie listy, to obie muszą mieć taką samą długość. Jeśli mamy dwie strony WWW, muszą one mieć taką samą długość i jeśli jedna z nich zawiera osadzoną stronę, druga również musi zawierać taką stronę. Jeśli decydujemy, że dwa panrametry mają taki sam status i muszą być przetwarzane w sposób zsynchronizowany, możemy wybrać jeden z nich i zorganizować funkcję wokół niego. (3) Wreszcie, w rzadkich przypadkach, może nie być oczywistego związku pomiędzy dwoma parametrami. Dla takich danych wejściowych musimy analizować wszyst- kie możliwe przypadki, zanim opracujemy przykłady i zaprojektujemy szablon. Dla pierwszych dwóch przypadków stosujemy istniejącą metodę projektowania. Ostatni przypadek wymaga dodatkowych uwag. Po tym, jak zdecydujemy, że funkcja należy do trzeciej kategorii, ale zanim opracu- jemy przykłady i szablon funkcji, musimy opracować dwuwymiarową tabelę. Oto po- nownie tabela dla funkcji wybierz-z-listy: dana-lista-symboli (empty? dana-lista-symboli) (cons? dana-lista-symboli) n (= n 1) ( n 1) W kolumnach wyliczamy warunki rozróżniające podklasy pierwszego parametru, w wier- szach wyliczamy warunki dla drugiego parametru. Tabela pomaga w opracowaniu zarówno zbioru przykładów dla naszej funkcji, jak i jej szablonu. Jeśli chodzi o przykłady, muszą one pokrywać wszystkie możliwe przy- padki. Oznacza to, że musimy opracować przynajmniej po jednym przykładzie dla każ- dej komórki tabeli. 248 17. PRZETWARZANIE DWÓCH SKOMPLIKOWANYCH ELEMENTÓW DANYCH Jeśli chodzi o szablon, musimy w nim zawrzeć po jednej klauzuli wyrażenia cond dla każdej komórki. Każda z tych klauzul musi zawierać wszystkie możliwe selektory dla obu parametrów. Jeśli jeden z nich jest atomowy, nie ma oczywiście potrzeby stoso- wania selektorów. Wreszcie, zamiast pojedynczej naturalnej rekursji może zaistnieć ko- nieczność wprowadzenia wielu rekursji. Dla funkcji wybierz-z-listy znaleźliśmy trzy przypadki. Generalnie wszystkie możliwe kombinacje selektorów są potencjalnymi kan- dydatami do wykorzystania w naturalnej rekursji. Ponieważ nie możemy wiedzieć, które z nich są konieczne, a które nie są, wypisujemy je wszystkie i wybieramy te, które będą odpowiednie dla naszej definicji funkcji. Podsumowując, projektowanie funkcji dla wielu parametrów opiera się na pewnej odmianie starej metody projektowania. Kluczowe znaczenie ma przełożenie definicji da- nych na tabelę demonstrującą wszystkie możliwe i interesujące nas kombinacje. Two- rzenie przykładów dla funkcji i jej szablonu musi opierać się w jak największym stopniu właśnie na tej tabeli. Wypełnienie pustych przestrzeni w szablonie wymaga, jak zresztą wszystkie pozostałe czynności, praktyki. Ćwiczenia z przetwarzania dwóch złożonych danych wejściowych Ćwiczenia Ćwiczenie 17.8. Opracuj funkcję scalaj, która pobierze dwie listy liczb posortowane ro- snąco. Wynikiem funkcji będzie pojedyncza, posortowana lista liczb zawierająca wszyst- kie liczby z obu list (i żadnej innej). Poszczególne liczby powinny występować w liście wyjściowej tyle razy, ile razy pojawiły się w dwóch linstach wejściowych. Przykłady: (scalaj (list 1 3 5 7 9) (list 0 2 4 6 8)) ;; oczekiwana wartość: (list 0 1 2 3 4 5 6 7 8 9) (scalaj (list 1 8 8 11 12) (list 2 3 4 8 13 14)) ;; oczekiwana wartość: (list 1 2 3 4 8 8 8 11 12 13 14) Ćwiczenie 17.9. Celem tego ćwiczenia jest opracowanie nowej wersji gry w szubienicę z rozdziału 6. dla słów o dowolnej długości. Stwórz definicję danych reprezentujących słowa dowolnej długości za pomocą list. Litera powinna być reprezentowana przez symbole od a do z oraz symbol _. Opracuj funkcję odslon-liste, która pobierze trzy argumenty: (1) Wybrane słowo, które należy odgadnąć. (2) Słowo statusu, które określa, jak dużą część słowa odgadliśmy do te pnory. (3) Literę, która reprezentuje naszą aktualną próbę. ĆWICZENIA Z PRZETWARZANIA DWÓCH ZŁOŻONYCH DANYCH WEJŚCIOWYCH 249 Funkcja zwróci nowe słowo statusu, które składa się z dowolnych liter i znaków _. Pola w nowym słowie statusu określamy porównując próbę z każdą parą liter ze słowa statusu i wybranego słowa: (1) Jeśli próba jest równa danej literze w wybranym słowie, wstawiamy tę literę w od- powiednie miejsce w słowie statusu. (2) W przeciwnym przypadku nowa litera odpowiada literzne ze słowa statusu. Przetestuj funkcję odslon-liste dla następujących przykładów: (odslon-liste (list t e a) (list _ e _) u) (odslon-liste (list a l e) (list a _ _) e) (odslon-liste (list a l l) (list _ _ _) l) Określ — najpierw ręcznie — jakie powinny być rezultatny powyższych wywołań. Zastosuj pakiet szkoleniowy hangman.ss i funkcje dorysuj-nastepna-czesc (patrz ćwi- czenie 6.27) oraz odslon-liste, aby rozegrać grę w szubienicę. Oblicz także wartość nastę- pującego wyrażenia: (hangman-list odslon-liste dorysuj-nastepna-czesc) Funkcja hangman-list (udostępniona we wspomnianym pakiecie nauczania) wybiera lo- sowe słowo i wyświetla okno z menu wyboru liter. Wybierz litery i gdy będziesz gotowy, kliknij przycisk Check, aby sprawdzić, czy Twój strzał był trafny. Powodzenian! Ćwiczenie 17.10. Robotnicy w fabryce podbijają swoje karty czasowe rano, gdy przy- chodzą do pracy, i po południu — gdy wychodzą. Obecnie stosuje się elektroniczne karty zawierające numer pracownika i liczbę przepracowanych godzin. Ponadto akta pracow- nika zawierają zawsze jego nazwisko, numer i stawkę ngodzinową. Opracuj funkcję godziny- wynagrodzenia2, która pobierze listę akt pracowniczych oraz listę (elektronicznych) kart. Funkcja będzie obliczać miesięczne wynagrodzenie każdego pracownika odpowiednio dopasowując, na podstawie numeru pracownika, dane z jego akt z danymi zapisanymi na karcie. Jeśli zabraknie danej pary lub numery pracowników nie będą się zgadzać, funkcja zatrzyma się z odpowiednim komunikatem o błędzie. Załóż, że istnieje co najwyżej jedna karta dla jednego pracownika i dla odpowiadającemu mu numeru. Wskazówka: Księgowy posortowałby najpierw obie listy według numernów pracowników. Ćwiczenie 17.11. Kombinacja liniowa jest sumą kilku składników liniowych, co oznacza, że zwraca zmienne i liczby. Te drugie nazywamy w tym kontekście współczynnikami. Oto kilka przykładów: 5 ∗ x 5 ∗ x + 17 ∗ y 5 ∗ x + 17 ∗ y + 3 ∗ z We wszystkich trzech przykładach współczynnikiem przy x j
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Projektowanie oprogramowania. Wstęp do programowania i techniki komputerowej
Autor:
, , ,

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: