Skip to content

Instantly share code, notes, and snippets.

@jiribenes
Last active February 17, 2022 12:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jiribenes/ac8c928abea351ccf30efd5f1cbb4f21 to your computer and use it in GitHub Desktop.
Save jiribenes/ac8c928abea351ccf30efd5f1cbb4f21 to your computer and use it in GitHub Desktop.
Cvičení z Neprocedurálního programování - 1 - Prolog jako databáze faktů
%%% Prolog jako databáze faktů:
% Otevřete SWI Prolog a tento soubor.
% Tento soubor nahrajte (zkonzultujte) ve SWI Prologu
% pomocí příkazu `consult('<cesta k souboru>.pl')`.
% Po každé změně napište `make.` pro reloadnutí.
%%% Syntaxe Prologu:
% :- se čte jako "if"/"pokud"
% . se čte jako "end"/"konec"
% , se čte jako "and"/"a zároveň"
% ; se čte jako "or"/"nebo"
%%% Zadání:
% Chceme vytvořit systém práv pro kanceláře
% Administrátoři
admin(jirka). % `jirka` je nějaká konstanta, `admin(Osoba)` je predikát, který platí, pokud je `Osoba` administrátorem.
admin(petr).
%% Vyzkoušejte ve SWI Prologu dotazy [napište tam tu řádku začínající `?-`, samotný prefix `?-` neopisujte]
% ?- admin(jirka).
% true.
%
% ?- admin(pavel).
% false.
%
% ?- admin(X). % `X` je tady proměnná, za kterou se Prolog bude snažit dosazovat
% X = jirka ; % tady vám to vypíše jen jeden výsledek, zmáčkněte `;` na klávesnici, aby vám prolog vypsal další
% X = petr.
% Účetní oddělení
uctar(ferda).
uctar(ferda2). % kreativní pojmenování další osoby :D
% Sami si vyzkoušejte dotazy: `uctar(jirka)`, `uctar(X)`.
% Ferda dělá fakt dobrý kafe!
dela_dobre_kafe(ferda).
% Predikát `smi_do_mistnosti(Osoba, Mistnost)` odpoví true, pokud daná Osoba smí do dané Místnost-i
% Admini smí kamkoliv
% čteme jako "osoba smí do jakékoliv místnosti, pokud je osoba adminem"
smi_do_mistnosti(Osoba, _) :- admin(Osoba). % `_` ignoruje proměnnou (tohle pomůže proti warningům)
% Rozmyslete si, že proměnné v klauzuli (před `:-`) jsou obecně kvantifikované (s provšechnítkem!).
% Vyzkoušejte dotaz `smi_do_mistnosti(jirka, serverovna)`.
% Účtaři smí do účtárny
smi_do_mistnosti(Osoba, uctarna) :- uctar(Osoba).
% Následující řádka se čte jako
% smi_do_mistnosti(Osoba, jidelna_vedle_uctarny) if uctar(Osoba) and dela_dobre_kafe(Osoba)
smi_do_mistnosti(Osoba, jidelna_vedle_uctarny) :- uctar(Osoba), dela_dobre_kafe(Osoba).
% Všichni smí na záchod a do únikového východu
smi_do_mistnosti(Osoba, zachod).
smi_do_mistnosti(Osoba, unikovy_vychod).
% Vyzkoušejte dotazy:
% smi_do_mistnosti(X, uctarna).
% smi_do_mistnosti(jirka, X).
% smi_do_mistnosti(Osoba, Mistnost).
% a rozmyslete si proč vám Prolog odpovídá tak jak odpovídá
%%% Společně jsme psali tohle:
% den_po(Den1, Den2):
% Den2 je ten den, který je po Den1
den_po(pondeli, utery).
den_po(utery, streda).
den_po(streda, ctvrtek).
den_po(ctvrtek, patek).
den_po(patek, sobota).
den_po(sobota, nedele).
den_po(nedele, pondeli).
% den_pred(Den2, Den1) s využitím `den_po`:
den_pred(Den2, Den1) :- den_po(Den1, Den2).
% Vyzkoušejte dotazy:
% den_po(pondeli, X).
% den_po(X, Y).
% den_po(X, X).
% den_pred(X, patek), den_pred(Y, X).
% A ------> B ---> C
% \ \ /|
% \| \| /
% E----------->F
% \ /|
% \| /
% D /
% /| /
% / /
% G ---> H
%
% Cesty z A do C:
%
% A, B, C
% A, B, F, C
% A, E, F, C
edge(a, b).
edge(a, e).
edge(b, c).
edge(b, f).
%edge(c, a). % Tahle hrana vytvoří cyklus [zkuste odmazat]
edge(e, d).
edge(e, f).
edge(f, c).
edge(g, d).
edge(g, h).
edge(h, f).
% Chceme definovat 'path(U, V)', který značí jestli existuje orientovaná cesta z U do V
% Hranu z U do V značím jako U -> V
% Orientovanou cestu z U do V značím jako U ~~~> V
% U -> V
path(U, V) :- edge(U, V).
% U -> W ~~~> V
path(U, V) :- edge(U, W), path(W, V).
% Rozmyslete si, že `W` je tady nutně kvantifikovaná _existenčně_ (existítkem) a ne _obecně_ (provšechnítkem).
% Vyzkoušejte `path(a, c)`. Mělo by vypsat `true; true; true; false`.
% Rozmyslete si proč :)
% Dále jsme si v tuto chvíli ukázali `trace.` pro debuggování. [Pomocí `notrace.` zase vypnete!]
% Zkuste spustit `trace.` a potom `path(a, c).`
% Mačkejte tlačítko `Enter` na klávesnici a koukejte co Prolog dělá :)
% Měli byste si tím potvrdit hypotézu, kterou jste si formulovali výše.
% Vyzkoušejte si všechny možné způsoby jak zavolat `path`:
% `path(a, c)`
% `path(X, c)`
% `path(a, Y)`
% `path(X, Y)`
%%%%% Zadání
% Vyhodnoťte logickou formuli:
%
% a(X, Y) ... (X /\ Y)
% nebo(X, Y) ... (X \/ Y)
% ne(X) ... ~X
%
%
% pla ... T
% nepla ... F
% Zavolejte `priklad(Z)` ve SWI Prologu
% a Prolog vam vypise pravdivost formulky
priklad(Z) :-
Formulka = a(pla, ne(nebo(nepla, pla))), % T /\ ~(F \/ T)
vyhodnot(Formulka, Z).
vyhodnot(pla, pla). % pravda se vyhodnotí na pravdu
vyhodnot(nepla, nepla). % nepravda se vyhodnotí na nepravdu
vyhodnot(ne(X), nepla) :- vyhodnot(X, pla). % negace X je nepravdivá, pokud X je pravdivé
vyhodnot(ne(X), pla) :- vyhodnot(X, nepla). % negace X je pravdivá, pokud je X nepravdivé
% konjunkce
vyhodnot(a(X, Y), Z) :-
vyhodnot(X, HX), % nejprve vyhodnotíme levý člen
vyhodnot(Y, HY), % ... a pravý člen
% máme jen pár možností jak to celé může dopadnout:
( (HX=pla, HY=pla, Z=pla) % (T /\ T) = T
; (HX=nepla, Z=nepla) % (F /\ _) = F
; (HY=nepla, Z=nepla) % (_ /\ F) = F
).
% disjunkce
vyhodnot(nebo(X, Y), Z) :-
vyhodnot(X, HX),
vyhodnot(Y, HY),
( (HX=pla, Z=pla) % (T \/ _) = T
; (HY=pla, Z=pla) % (_ \/ T) = T
; (HX=nepla, HY=nepla, Z=nepla) % (F \/ F) = F
).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment