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 adam
a. 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:
- Najděte filmy, ve kterých hraje jejich režisér.
- Vytvořte predikát
filmy_starsi_nez(Rok, Film)
, který platí, pokudFilm
vyšel před rokemRok
. - Najděte herce, kteří hrají alespoň ve dvou filmech.
- Přímo v odkazovaném souboru je také několik otázek, zkuste je vyřešit.