|
2. Procedury rekurencyjne
Podejście stosowe zakłada rekurencję jako własność oczywistą. Umożliwienie określania parametrów procedur w postaci zapytań oraz zwracania wyniku procedur w postaci dowolnej wartości dziedziny Rezultat stwarza nową jakość, która dotychczas była kwalifikowana jako własność "inteligentna", specyficzna dla dedukcyjnych baz danych. Za pomocą rekurencyjnych procedur można bez trudu osiągnąć efekty omawiane poprzednio dla tranzytywnych domknięć oraz równań stałopunktowych. Jak się okazuje, mimo różnic składniowych i semantycznych, są to mechanizmy porównywalne pragmatycznie. Z doświadczeń autora wynika, że procedury rekurencyjne są bardziej zrozumiałe dla powszechnego programisty, być może wskutek praktyki edukacyjnej.
P15.8. |
Patrz Rys.71. Procedura Podczęści ma parametr mojeCzęści bedący bagiem referencji do części. Procedura zwraca bag z referencjami do wszystkich podczęści części wymienionych w parametrze. Duplikaty w wyniku nie są usuwane. Przy transmisji parametrów przyjmujemy metodę ścisłego wołania przez wartość.
procedure Podczęści( mojeCzęści) {
return if not exists(mojeCzęści) then
bag{}
else
bag( mojeCzęści, Podczęści(mojeCzęści.składnik.prowadziDo.Część))}
Procedura zwraca części występujące w argumencie, następnie nawiguje do ich bezpośrednich podczęści i wywołuje sama siebie. W momencie, gdy dany obiekt nie będzie miał podobiektu Składnik, argument procedury Podczęści będzie pusty, co zakończy jej działanie.
Podaj nazwy wszystkich części detalicznych składających się na samolot Boening 767:
distinct( Podczęści( Część where nazwa = "Boening 767" )
where rodzaj = "detal").nazwa
|
P15.9. |
Patrz Rys.71. Procedura PodczęściIle ma parametr mojeCzęściIle w postaci zapytania zwracającego bag struktur struct{ c(r), ile(v) }, gdzie c(r) jest binderem, w którym r jest referencją do obiektu część, ile(v) jest binderem w którym v jest liczbą nieujemną. Liczba v ustala ilość części z referencją r. Procedura zwraca bag struct{c(r1), ile(v1)} specyfikujący podczęści wszystkich części wymienionych w parametrze procedury: r1 jest referencją do podczęści, zaś v1 jest ilością tych podczęści niezbędnych do złożenia ilości części wymienionych w parametrze procedury. Duplikaty zwracanych referencji nie są usuwane, jak również nie są sumowane ilości podczęści wynikające z różnych dróg dotarcia do danej podczęści w strukturze część/podczęść.
procedure PodczęściIle( mojeCzęściIle) {
return if not exists(mojeCzęściIle) then
bag{} else bag( mojeCzęściIle,
(mojeCzęściIle.PodczęściIle(c.(składnik.(
(prowadziDo.Część) as c, (ile * ilość) as ile)))))}
Jeżeli bag będący argumentem procedury jest niepusty, to procedura zwraca wszystkie elementy tego bagu, plus elementy zawierające informację o ich podczęściach. W tym celu konieczne jest przemnożenie ilości danej części w argumencie procedury z ilością jej bezpośredniej podczęści.
Planuje się wyprodukowanie 68 samolotów B767 oraz 135 samolotów B747. W tej chwili jest przygotowywana umowa z kooperantem dostarczającym wkręty o nazwie "M5x70" niezbędne do produkcji samolotów. Ile wkrętów należy zamówić?
sum(
PodczęśćIle( bag((Część where nazwa = "B767") as c, 68 as ile),
(Część where nazwa = "B747") as c, 135 as ile))).
where c.nazwa = "M5x70").ile)
|
P15.10. |
Obiekty Osoba mają atrybuty nazwisko, rokUr (rok urodzenia), żyje (z wartością boolowską) oraz są powiązane związkami rodzinnymi matka, ojciec, syn, córka, zaimplementowanymi jako obiekty pointerowe umieszczone wewnątrz obiektów Osoba. Procedura Przodek zwraca wszystkich przodków osób zakomunikowanych jako parametr. Procedura Następca zwraca wszystkich następców osób zakomunikowanych jako parametr. Każda osoba jest jednocześnie swoim przodkiem i następcą.
procedure Przodek( mojeOsoby) {
return if not exists(mojeOsoby) then bag{}
else distinct( bag(mojeOsoby,
Przodek(mojeOsoby.(matka È ojciec).Osoba)))}
procedure Następca( mojeOsoby) {
return if not exists(mojeOsoby) then bag{}
else distinct( bag(mojeOsoby,
Następca (mojeOsoby.(syn È córka).Osoba)))}
Podaj nazwisko i rok urodzenia wszystkich żyjących kuzynów Kowalskiego, którzy są od niego młodsi:
(((Osoba where nazwisko = "Kowalski") as kow) join
(Następca(Przodek( kow )) as kuzyn)
where (kow.rokUr > kuzyn.rokUr and kuzyn.żyje)).
(kuzyn.(nazwisko, rokUr)) |
|