Josef Troch (troch@mail.ru)
25.03.2003 (poslední změna 01.04.2003)

Rock & Roll - deduktivní objektově orientovaný DB systém

Co to je?

Rock & Roll je deduktivní objektově orientovaný DB systém. Jeho domovská stránka je tady, ale už přes 4 roky nebyla změněna. Všechny odkazy na stažení Rock & Roll-u tam uvedené jsou neplatné, momentálně ho lze nalézt zde.

Skládá se ze 2 jazyků:

Instalace, verze atp.

Rock & Roll je k dispozici pro tyto platformy:

Základy

Rock & Roll funguje jako interpreter. Po spuštění programu (rnr pro nepersistentní versi, prnr pro persistentní versi) se objeví příkazová řádka, která akceptuje mimo jiné tyto příkazy:
helpHelp:-)
run soubor_s_programemZkompiluje a začne interpretovat daný program.
compile jmeno_metodyZkompiluje Roll metodu.
execute jmeno_metodySpustí Roll metodu.
list_compiledVypíše detaily o zkompilovaných Roll metodách.
quitOpustí systém commitujíce změny.
abortOpustí systém abortujíce změny.

Struktura programu

program <seznam parametrů>
begin
  <definice>
  <deklarace>
  <vlastní tělo programu>
end

Rock

Rock se skládá z "data definition language" pro definici schémat a "data manipulation language" pro správu dat. Dále podporuje interakci s uživatelem a souborové I/O. V Rocku se rozlišuje mezi: Pro každý type existuje právě 1 class a naopak.

Pozn.: Komentáře v Rock-u fungují vždy do konce řádku a začínají znakem '#'.

Type

Class

Nejdříve musí být deklarován příslušný type.

Příklad deklarace class i s příslušným type:
  
type date:
  public <dd: int, mm: int, yy: int>;   
  ROCK:
    print();
end-type

class date:
  public:              #až zde se deklaruje private/public
    print()            #signatura metody
    begin              
      write get_dd()@self, ":", get_mm()@self(), ":", get_yy()@self;
    end
end-class

Data Manipulation Language

Roll

Roll je deduktivní dotazovací jazyk odpovídající Datalogu se stratifikací.

Dotaz

... může být 3 druhů:
  1. [| goal_set] - žádný "projection list" -> výsledek jen true/false - př.: [| get_plat@P == M, M < 20000] (dotaz, zda existuje zaměstnanec s platem < 20000)
    Pozn.: Roll odhaduje typy logických proměnných z dotazů nebo metod - zamestnanec je jediný typ mající metodu get_plat, takže ho to najde. Kdyby mělo více tříd stejnojmennou metodu, bylo by třeba psát uvedený dotaz takto: [| get_plat@P:zamestnanec == M, M < 20000]]
    Takovýto dotaz lze v programu použít jako boolovský výraz - třeba jako podmínku v if-then-else atp.
  2. [ any projection_list | goal_set] - hledá se pouze jedno řešení (jako v Prologu) - př.: [any P get_plat@P:zamestnanec == M, M < 20000]] Výsledek tohoto dotazu se dá přiřadit do proměnné typu zamestnanec (obecně je výsledkem "aggregation" ("n-tice")) - a pak s ním manipulovat pomocí Rock-u.
  3. [ all projection_list | goal_set] - výsledkem jsou všechny objekty (resp. jejich projekce) splňující pravou stranu nasypané do "association" (neexistuje-li žádný splňující objekt -> prázdná "association"). Př.:
            
    var partSet :{part};
    partSet := [all P | get_mass@P:base_part == M, M < 5.0]
    foreach p in partSet do ....
    
    var nmSet := [all <M,N> | get_mass@P:base_part == M, M < 5.0, get_name@P == N];
    foreach v in nmSet do ...
    
    Pozn.: Zápis [ {projection_list} | goal_set] je ekvivalentní s výše uvedeným.

Dále k syntaxi

Metody

Příklad

Tento příklad je počeštěnou a výrazně zjednodušenou verzí jednoho z příkladů dodávaných s Rock & Roll-em verse 4.00. Kompletní kód tohoto programu lze nalézt zde.

Budeme mít velmi jednoduchou databázi informací o příbuzenských vztazích. Nejdřív nadefinujeme typy/třídy objektů:
program osoba
begin
    type osoba:
	properties:
	  public:
	    jmeno: string,
	    vek: int,
	    otec: muz,
	    matka: zena;
	    
	ROCK:
	    vynasob_vek(times: int): int;
	    
	ROLL:
	    rodic(osoba),
	    sourozenec(osoba), 
	    predek(osoba);
    end-type

    type muz:
	specialises: osoba;
    end-type

    type zena:
	specialises: osoba;
    end-type

    class osoba                                   
      public:
	vynasob_vek(times: int) : int
	begin
	    get_vek@self * times
	end
	
	rodic(osoba)
	begin
	    rodic(F)@Self :- get_otec@Self:osoba == F;
	    rodic(M)@Self :- get_matka@Self:osoba == M;
	end
	
	predek(osoba)
	begin
	    predek(G)@P :- rodic(G)@Z, predek(Z)@P;
	    predek(G)@P :- rodic(G)@P;
	end
	sourozenec(osoba)
	begin
	    sourozenec(X)@Y :-	X =\= Y, rodic(P)@X, rodic(P)@Y;
	end
    end-class
Teď bychom měli databázi nějak naplnit - vzhledem k tomu, že jsme nenadefinovali parametrický konstruktor pro osobu, nezbývá nám, než to udělat nějak takto:
    var adam := new muz();
    var eva := new zena();
    var abel := new muz();
    # ...

    put_vek(70)@adam;
    put_vek(69)@eva;
    put_vek(40)@abel;
    put_jmeno("adam")@adam;
    put_jmeno("eva")@eva;
    put_jmeno("abel")@abel;

    put_otec(adam)@abel;
    put_matka(eva)@abel;
Teď by měl následovat vlastní program. V našem případě jednoduché dotazy, zabalené do nějakých vhodných výpisů na obrazovku - zde je jeden vzorový, dále uvedu už jen pár dotazů
    write "Predci pro jednotlive osoby", nl,
	"Dotaz: [ {A} | predek(A)@!p ]", nl, nl;

    foreach p in osoba do
    begin
	var ancs := [ {A} | predek(A)@!p ];
	write "Předci pro: ", get_jmeno()@p, nl;

	foreach a in ancs do
	begin
	    write "	", get_jmeno()@a, nl;
	end
... a na závěr programu by ho to chtělo ještě ukončit:
end
Nyní ty slíbené další dotazy:

Všechny dvojice <předek, potomek>:[ {<A,P>} | predek(!A)@P ]
Nepřímí potomci Adama:[ {X} | predek(!adam)@X, ~ rodic(!adam)@X ]
Všechny dvojice sourozenců:[ {<X, Y>} | sourozenec(Y)@X ]
Osoby, nejmenující se Adam:[ all P | get_jmeno@P =\= Adam ]
... a pokud nám stačí jen 1 taková:[ any P | get_jmeno@P =\= Adam ]
Lidé, jejichž dvojnásobek věku je menší než 80:
(Jen jako příklad volání metody Rock-u.)
[ {<A, P>} | vynasob_vek(2)@P == A, A < 80 ]


Máte-li zájem o složitější příklad zkuste některý z příkladů dodávaných s Rock & Roll -em. V něm ovšem nejspíš narazíte na "environments", o kterých se tu tedy raději letmo zmíním.
"Environment" je jakási kolekce instancí tříd (a zároveň informací o tom, jak příslušná třída vypadá). Standartně se instance třídy "ukládají" do "run-time environment"-u, který se po skončení interpretovaného programu vždy vymaže. Jiný "environment" tedy potřebujete jen pokud chcete třídu v 1 programu nadefinovat/vytvořit instance a v druhém programu ji/je použít. "Environment" vytvoříte příkazem define_env jmeno_environmentu a použijete ho při spouštění programu takto: run jmeno_programu jmeno_environmentu. Podrobnější informace lze dohledat v níže uvedeném manuálu.

Zdroje:



Tento článek smí být používán libovolně, za předpokladu, že nebude modifikován a že takto bude učiněno se zmínkou o autorovi a odkazem na stránku http://jt.sf.cz, odkud by měla být dostupná aktuální verse tohoto článku.
Snažím se, aby informace zde uvedené byly pravdivé a pokud možno přesné, nicméně nenesu žádnou odpovědnost za to, že tomu tak opravdu je, ani za jakékoli škody, které by někomu v důsledku případných špatných či nepřesných informací z tohoto článku mohly vzniknout.



Jakékoliv dotazy či připomínky mi můžete poslat mailem.

Zpět na stránku referátů a jiných výtvorů