Kapitola 15: Dynamická databáze – Učíme program se učit

Doposud byly naše programy jako vytesané do kamene. Všechna fakta (kdo je rodič, kdo je muž) jsme napsali do souboru, spustili Prolog a hotovo. Pokud se narodilo nové dítě, museli jsme vypnout program, přepsat soubor a znovu spustit. To je v pořádku pro rodokmen historických králů, ale k ničemu pro hru nebo chatbota, který se má učit nové věci "za běhu".

V této kapitole se naučíme pracovat s dynamickou databází. Naučíme Prolog, aby si dělal poznámky, pamatoval si skóre, nebo se dokonce učil nová pravidla přímo během konverzace s vámi.

15.1 Paměť počítače: Kniha vs. Zápisník

Představte si paměť Prologu jako dvě různé věci:

STATICKÁ DATABÁZE (KNIHA) To je váš kód v souboru .pl. Je to jako vytištěná kniha. Můžete v ní číst, ale nemůžete do ní psát. Když program běží, tato fakta se nemění.
DYNAMICKÁ DATABÁZE (ZÁPISNÍK) Část paměti, kterou může program sám měnit. Může si sem "přilepit" lísteček s novou informací nebo ho "vyhodit". Tyto změny existují jen v paměti RAM – když program vypnete, zápisník se vymaže (pokud ho neuložíte do souboru).

15.2 Jak měnit realitu: Assert a Retract

Abychom mohli měnit fakta za běhu, musíme Prologu nejdříve říct, že daný predikát bude dynamický. Děláme to příkazem :- dynamic na začátku souboru.

Poté používáme dvě kouzelná slova:

Magická kniha
Obrázek 15.1: Dynamická databáze je jako magická kniha, která se sama přepisuje.

Řešené příklady: Inventář v RPG hře

Představte si, že hrajete hru. Hrdina chodí po světě a sbírá předměty. Musíme si pamatovat, co má v batohu.

% 1. Řekneme Prologu, že 'mam' se bude měnit
:- dynamic mam/1.

% Na začátku nemáme nic (nebo můžeme napsat: mam(meč).)

% Pravidlo pro sebrání věci
seber(Vec) :-
    assert(mam(Vec)),           % Přidáme fakt do paměti
    write('Sebral jsi '), write(Vec), nl.

% Pravidlo pro zahození věci
zahod(Vec) :-
    retract(mam(Vec)),          % Zkusíme fakt vymazat
    write('Zahodil jsi '), write(Vec), nl.

zahod(Vec) :-                   % Co když tu věc nemáme? (retract selže)
    write('Nemůžeš zahodit '), write(Vec), write(', protože ji nemáš!'), nl.

% Výpis inventáře
inventar :-
    write('Máš u sebe:'), nl,
    mam(X),                     % Najdi něco, co mám
    write('- '), write(X), nl,
    fail.                       % Vynuť backtracking, aby našel další věci
inventar.                       % Konec (když už nic nenajde)

Jak to funguje v konzoli:

?- seber(klic).
Sebral jsi klic.
true.

?- mam(klic).
true.

?- zahod(klic).
Zahodil jsi klic.
true.

?- mam(klic).
false.

15.3 Pořadí záleží: Asserta vs. Assertz

Když přidáváte fakt, kam se zařadí? Na začátek nebo na konec? Někdy je to jedno (inventář), ale někdy je to klíčové (pravidla, která se zkouší popořadě).

Klíčový koncept: Sebe-modifikující kód

Prolog je jedním z mála jazyků, kde je hranice mezi "daty" a "kódem" velmi tenká. Když použijete assert, doslova měníte program, který běží. Můžete přidávat nejen fakta, ale i celá pravidla! To umožňuje vytvářet systémy, které se učí ze zkušenosti.

Otázky k zamyšlení

  1. Co se stane, když zapomenete napsat :- dynamic a pokusíte se použít assert na nějaký predikát? (Prolog vyhlásí chybu o modifikaci statické procedury).
  2. Zmizí dynamická fakta, když vypnu Prolog? Proč? (Ano, jsou jen v RAM. Pokud je chcete uchovat, musíte je uložit do souboru).
  3. Kdy byste použili asserta místo assertz? (Například když chcete přidat výjimku z pravidla, která se má zkontrolovat před obecným pravidlem).

🧪 Laboratoř: Paměť pro chatbota