Predikatoj, klaŭzoj, reguloj.

Por adicii romajn ciferojn ni devas difini regulojn kiel fari tion. Ni komencu tute simple:

roma_cifero('I',1).
roma_cifero('V',5).
roma_cifero('X',10).
roma_cifero('L',50).
roma_cifero('C',100).
roma_cifero('D',500).
roma_cifero('M',1000).

roma_sumo(C1,C2,Sumo) :-
    roma_cifero(C1,V1),
    roma_cifero(C2,V2),
    VS is V1 + V2,
    roma_cifero(Sumo,VS).

Do, kion faras la regulo roma_sumo? Ĝi eltrovas la valorojn de la du donitaj ciferoj, adicias ilin kaj trovas roman ciferon, kies valoro egalas al la sumo. Nu, tio funkcias nur esceptokaze, ĉar la sumo kutime ne hazarde respondas al alia cifero. Jen elprovu:

roma_sumo('V','V',Sumo).

Antaŭ plibonigi tion, ni lernu ankoraŭ kelkajn terminojn: La nomojn de la kombinoj per kiujn ni donas faktojn kaj regulojn, nomiĝas predikatoj. Ili konsistigas rilaton inter siaj argumentoj: La predikato roma_cifero difinas rilatojn inter la ciferoj I, V, X,… kaj iliaj valoroj (skribitaj kiel arabaj nombroj). La predikato roma_sumo difinas rilaton inter du ciferoj kaj tria cifero, kiu estas ilia sumo.

Ĉar la nombro de argumentoj gravas, por distingi samnomajn predikatojn kun diversa nombro de argumentoj oni konvencie indikas tiujn: roma_cifero/2, roma_sumo/3.

Celo estas predikato, pri kies vereco Prologo trovu pruvon. La uzanto donas komencan celon kiel demandon. Dum la pruvo, Prologo povas krei novajn celojn el la korpoj de reguloj, tiuj nomiĝas subceloj.

Faktoj kaj reguloj estas ambaŭ klaŭzoj. Fakto estas klaŭzo sen korpo, dum regulo konsistas el kapo (la parto antaŭ :-) kaj korpo.

Kiam Prologo provas pruvi celon, ĝi serĉas klaŭzon, kies kapo unuiĝas kun la aktuala celo. Se tia unuiĝo sukcesas, la koncernaj variabloj en la argumentoj de la kapo ligiĝas al la transdonitaj valoroj (t.e. ne nepre ĉiuj, kelkaj povas resti liberaj kaj ligiĝi dum la pruvo pri la korpo).

  • Se la klaŭzo estas fakto, la celo estas tuj pruvita, ĉar la ellasita korpo impliciĝas kiel true. (t.e. vera).
  • Se la klaŭzo estas regulo, tiam Prologo devas ankoraŭ pruvi ĉiujn celojn en la korpo de la regulo (kun la samaj variablaj ligoj). La regulo sukcesas nur se ĉiuj korpaj celoj sukcesas.

% la sumo de du ciferoj
% rezultas en alia cifero
roma_sumo_2(C1,C2,Sumo) :-
    roma_cifero(C1,V1),
    roma_cifero(C2,V2),
    VS is V1 + V2,
    roma_cifero(Sumo,VS).

% la unua cifero estas pli
% granda aŭ egala al la dua
roma_sumo_2(C1,C2,[C1,C2]) :-
    roma_cifero(C1,V1),
    roma_cifero(C2,V2),
    VS is V1 + V2,
    % ne ekzistas cifero de la sumo
    \+ roma_cifero(Sumo,VS),
    V1 >= V2.  

% la unua cifero estas malpli
% granda ol la dua
% via tasko!

roma_sumo_2('X','I',Sumo).

Ĉu vi kuraĝas aldoni trian regulon al la predikato roma_sumo_2/3 por la kazo kiam la unua nombro estas pli malgranda ol la unua?

Rilato inter klaŭzoj de Prologo kaj datumbazoj

Se vi estas familiara kun datumbazoj, vi eble jam rimarkis, ke fakto estas ekvivalenta al horizontalo en tabelo.

roma_cifero

roma val
‘I’ 1
‘V’ 5
‘X’ 10
‘L’ 50
‘C’ 100
‘D’ 500
‘M’ 1000

Demando al Prolog-programo kaj demando al datumbazo estas certagrade ekvivalentaj. Kaj regulo estas iom analoga al rigardo en datumbazo:

roma_sumo(C1,C2,Sumo) :-
    roma_cifero(C1,V1),
    roma_cifero(C2,V2),
    VS is V1 + V2,
    roma_cifero(Sumo,VS).

En SQL oni skribus ekzemple tiel:

CREATE VIEW roma_sumo AS
  SELECT r1.roma as C1, r2.roma as C2, sum.roma AS Sumo 
  FROM roma_cifero r1, roma_cifero r2, roma_cifero sum 
  WHERE sum.val = r1.val + r2.val;

Do anstataŭ , (kaj) en Prologo, en datumbazo oni uzas kunigon (angle: join). Tamen, ĉar Prologo estas plenkapabla programlingvo, ja reguloj estas multe pli esprimkapablaj ol SQL-komandoj, kiuj rapide longiĝas, komplikiĝas kaj tiam estas nur malfacile, tempopostule senerarigeblaj.