Assertz

Prolog-ohjelmassa on mahdollista muokata ohjelman tietämyskantaa suorituksen aikana metapredikaattien asserta/1 ja assertz/1 avulla. Asserta lisää parametrina saamansa säännön ohjelman alkuun, asserz loppuun. Niiden avulla voidaan säilyttää tietoja predikaatin suorituskertojen välillä muutenkin kuin kuljettamalla niitä parametreina.

Gprologissa on lisäksi mahdollista käyttää globaaleja muuttujia, mutta se ei yleensä ole suositeltavaa, koska se rikkoo logiikkaohjelmoinnin paradigmaa vastaan. Assertointikin on tässä suhteessa arveluttavaa, mutta usein välttämätöntä. Jotta ongelmat, joita siitä, että ohjelma muokkaa itseään, voi aiheutua, saataisi pidettyä mahdollisimman vähäisinä, on kannattaa tietojen poistamista tietämyskannasta välttää. Tietämyskantaan saa lisätä ainoastaan sellaisia tietoja, joiden tiedetään pysyvän tosina ohjelman suorituksen loppuun asti. Tämän vuoksi myös asserta:ta ei pitäisi käyttää siten, että se vaikuttaa muuhun kuin ohjelman nopeuteen ja järjestykseen, jossa ratkaisut löytyvät. Asserta:n avulla olisi nimittäin mahdollista käytännössä poistaa faktoja, lisäämällä niiden komplementti ohjelman alkuun. Toisinaan on kuitenkin tehokkuussyistä järkevää käyttää alkuun lisäystä loppuun lisäyksen sijasta.

Jotta predikaattia voisi muokata ohjelman ajonaikana, tulee predikaatti määritellä dynaamiseksi tähän tapaan:

:-dynamic(isa/1).

Kokeillaanpa asserttia käytännössä:


| ?- assertz(isa(matti,jussi)).

yes
| ?- isa(X,jussi).

X = matti

yes
| ?- assertz(isa(matti,pekka)).

yes
| ?- asserta(isa(matti,antti)).

yes
| ?- isa(matti,X).             

X = antti ? ;

X = jussi ? ;

X = pekka

yes

Samaa kaavaa ei kannata assertoida montaa kertaa, vaan jos on olemassa mahdollisuus, että näin käy, tulee ensin kokeilla, onko kaava jo olemassa. Tämä tapahtuu esimerkiksi metapredikaatin clause/2 avulla:

| ?- assertz(isa(matti,jussi)).

yes
| ?- assertz((vanhempi(X) :- isa(X,Y))).

yes
| ?- vanhempi(X).

X = matti

yes
| ?- clause(vanhempi(X), isa(X,Y)).

yes
| ?- clause(vanhempi(matti), isa(X,Y)).

X = matti

yes
| ?- clause(vanhempi(matti), isa(jussi,Y)).

no

Esimerkkiohjelma 2: Labyrintti

Toiseksi esimerkkiohjelmaksi tein yksinkertaisen ruudukkomaisessa labyrintissä liikuskelevan kultaa etsivän agentin. Agentti näkee onko naapuriruuduissa esteitä, muttei sitä onko niissä kultaa. Löytääkseen kullan agentti liikkuu johonkin esteettömään naapuriruutuun, mikäli ei ole siellä vielä käynyt. Jokaisessa ruudussa agentti assertoi tiedon, että siellä on jo käyty. Predikaatti search onnistuu, mikäli kulta löytyy, ennen kuin agentti jää jumiin ruutuun, jonka naapureihin ei voi siirtyä. Selvästikään agentti ei ole kovin älykäs eikä löydä edes kaikkia niitä kulta-aarteita, jotka olisi mahdollista löytää muuttamalla etsintäjärjestystä, mutta yksinkertaisuutensa vuoksi se sopii hyvin esimerkiksi. Yksinkertaisuuden vuoksi myös agentin ympäristö on kovakoodattu ohjelmaan.

Ohjelman voi konsultoida tulkkiin ja esittää sille kyselyn:

| ?- search(location(3,3)).

true ? 

yes
| ?- search(location(3,3)).

no

Kysely onnistuu ensimmäisellä kerralla, mutta ei toisella. Miksi? No, ohjelma muistaa, että kullan luo johtavissa ruuduissa on jo käyty.