Prolog - úvod a program na rodinné vztahy

Program v prologu je v zásadě databáze faktů a vztahů mezi nimi napsaná pomocí Hornovských klauzulí. Každá klauzule je napsaná ve tvaru H:-B., kde H je hlava klauzule a B je její tělo. Můžete si to představovat i tak, že :- je šipka doleva (tedy implikace zprava doleva), a přesně takový je také význam klauzule. Klauzule mohou mít i prázdné tělo. Potom se píše jen H. Například následující 4 klauzule říkají, že (postupně), honza, adam, david a jiri jsou muži.

muz(honza). 
muz(adam).
muz(david).
muz(jiri).

Stejným způsobem další klauzule říkají, že jitka, jana a lida jsou ženy.

zena(jitka).
zena(jana).
zena(lida).

Klauzule mohou mít i více než jeden parametr. Následující klauzule vyjadřuje, ze honza je potomek adama. Podobně pro další klauzule.

%potomek(X, Y)
%X je potomek Y
potomek(honza, adam).
potomek(adam, david).
potomek(jiri, adam).

potomek(jitka, adam).
potomek(jitka, jana).

Pravidla, která platí mezi jednotlivými klauzulemi, se dají napsat pomoci klauzulí s tělem. Například fakt, ze když je X potomek Y, a zároveň je X žena, tak X je dcera Y. V logice bychom to mohli zapsat jako zena(X) & potomek(X,Y) -> dcera(X,Y). V Prologu napíšeme to samé, jen pomocí prologovské syntaxe, tedy:

dcera(X,Y):-zena(X),potomek(X,Y).
syn(X,Y):-muz(X),potomek(X,Y).

Všimněte si, ze jména konstant začínají malým písmenem a jména proměnných velkým. Podobně jako jsme právě nadefinovali dcera a syn, můžeme definovat i další rodinné vztahy.

deda(X,Y):-potomek(Y,Z),potomek(Z,X),muz(X).
bratr(X,Y):-potomek(X,Z),potomek(Y,Z),X \= Y,muz(X).

K čemu je zápis X\=Y v definici bratr? X\=Y znamená, že X a Y nejsou unifikovatelné. Bez tohoto atomu, bychom na dotaz bratr(jiri, X), dostali i odpověď, ze jiri je bratr sám sebe. A tím se dostáváme k dotazům a k tomu, co se Prologem dá vlastně dělat.

Úkol: Zkuste si pohrát s příklady v tomto textu, přidejte si další vztahy, nadefinujte si například predikáty teta, babicka, atd.

Tento soubor si můžete i stáhnout jako platný kód v Prologu. Pusťte si interpret Prologu, např. SWI-Prolog a zkuste tento soubor načíst (consult(cv1). – musíte být ve správném adresáři, pokud v něm nejste, použijte buď chdir('cesta/s/lomitky/dopredu'), nebo working_directory(_,'cesta/s/lomitky/dopredu/'). Funguje i zkratka [cv1]. a pokud máte příponu .pl asociovanou s Prologem, stačí na soubor normálně kliknout.

Nyní už můžete pokládat dotazy.

Dotazy se píší přímo v interpretu prologu, za prompt ?- (odpovědi Prologu jsou potom na samostatných řádkách). Nejjednodušší dotaz je například:

?- muz(jiri). 
true. 

Prolog odpovídá true, tzn. že byl schopen najít v databázi (nebo z ní odvodit), že dotaz je pravdivý. Podobně, když položíte dotaz:

?- dcera(jitka, jana).
true.

Prolog zase odpoví true, protože byl z databáze schopen odvodit, že jitka je dcera jany.

Můžete ale pokládat i složitější dotazy, které obsahuji proměnné, ty v Prologu musí začínat velkým písmenem:

?- dcera(X, jana). 
X = jitka ;
false.

V tomto případě vám Prolog odpoví, ze X je Jana, a čeká, co budete dělat. Když zmáčknete středník, pokusí se najít další X, které odpovídá dotazu, když se mu to nepovede, odpoví false.

Dotaz nemusí obsahovat vůbec žádné konstanty. V takovém případě Prolog najde všechna možná ohodnoceni proměnných v dotazu:

?- syn(X,Y).
X = honza,
Y = adam ;
X = adam,
Y = david ;
X = jiri,
Y = adam.

Úkol: Zkuste si trochu rozšířit naši databázi vztahů a napsat predikát predek(X, Y), který bude splněný v případě, že X je předek Y.

Zajímavější data

Naše databáze rodinných vztahů je relativně malá, můžeme si ale vyzkoušet práci s větší databází. Ve Swish (a na Githubu) je příklad s databází filmů, jejich režisérů a herců.

Můžeme nad ní zkoušet různé dotazy, například:

  1. Najděte filmy, ve kterých hraje jejich režisér.
  2. Vytvořte predikát filmy_starsi_nez(Rok, Film), který platí, pokud Film vyšel před rokem Rok.
  3. Najděte herce, kteří hrají alespoň ve dvou filmech.
  4. Přímo v odkazovaném souboru je také několik otázek, zkuste je vyřešit.