Arvsõnade semantika

Vaatleme järgnevas, kuidas õpetada Prologi aru saama sõnadega esitatud arvsõna tähendusest. Arvsõna (kümnendsüsteemis) koosneb osadest, milles on algul mingi number (1..9) ja siis kümne aste: kuus-tuhat--kolm-kümmend--viis = 6*1000 + 3*10 + 5.
Seega kõigepealt tuleb selgitada numbrite ja kümne astmete tähendus.
tähendus(null,0).
tähendus(üks,1).
tähendus(kaks,2).
tähendus(kolm,3).
tähendus(neli,4).
tähendus(viis,5).
tähendus(kuus,6).
tähendus(seitse,7).
tähendus(kaheksa,8).
tähendus(üheksa,9).
tähendus(kümme,10).
aste(kümmend,10).
aste(sada,100).
aste(tuhat,1000).

Arvsõna väärtus saadakse osade kaupa: (kuus-tuhat) + (kolm-kümmend) + viis = (6 * 1000) + (3 * 10) + 5 .
Tekstina esitatud arvsõna väärtuse arvutab lõpprekursiivne predikaat tõlgi, mis "loeb" arvsõna osade (number + aste) kaupa, leiab iga osa väärtuse ja lisab selle arvsõna juba loetud osa väärtusele.
Predikaadi esimene argument on arvsõna veel lugemata osa (tekst), teine argument on juba loetud osa väärtus (number), kolmas argu ment - osa lugemise järel saadav uus väärtus (number).
Kui kogu sõna on loetud, on teine ja kolmas argument loomulikult võrdsed; see reegel tuleb paigutada esimeseks:

tõlgi('',Arv,Arv) :-
!.
Kui järele jäänud osa on üks number (seda saab interpreteerida numbreid esitava predikaadiga tähendus), lisatakse see number juba loetud osa väärtusele:

tõlgi(ArvSõna,Loetud,Arv) :-
tähendus(ArvSõna,Number),
Arv is Loetud + Number.
Arvsõna interpreteerimise kõige olulisem reegel on:
- erista arvsõnas numbrist ja kümne astmest koosnev osa: kuus-tuhat-...
- leia nende väärtused ja lisa nende korrutis (s.t. kogu osa väärtus) arvsõna juba loetud osa väärtusele;
- seejärel rakenda sama reeglit arvsõna lõpposale.
Järgnevas predikaadi tõlgi kirjelduses on muutujate Arvsõna, Arvsõna1 väärtus alati "normaalne" arvsõna; Arvsõna1 on Arvsõna alamlõik, mis on saadud Arvsõna esimese osa (number+kümne aste) ärajätmisel. Muutuja Astearv on alati arvsõna, mis algab kümne astmega; see on saadud muutuja Arvsõna väärtusest esimese numbri ärajätmisega.

tõlgi(ArvSõna,Loetud,Arv) :-
tähendus(Sõna,Number),
atom_concat(S,AsteArv,ArvSõna),S = Sõna,
aste(AsteSõna,Aste),
atom_concat(A,ArvSõna1,AsteArv),A = AsteSõna,
!,
Loetud1 is Loetud + Aste * Number,
tõlgi(ArvSõna1,Loetud1,Arv).
Kuna süsteemipredikaati atom_concat saab kasutada vaid juhul, kui kaks esimest argumenti on mõlemad muutujad või on mõlematel väärtus, ei saa ülal kolmandas reas öelda "otse" atom_concat(Sõna,AsteArv,ArvSõna), sest muutujal Sõna on väärtus (sai eelmises reas), kuid muutujal AsteArv väärtust veel pole; seepärast tuleb kontrollida muutuja väärtust pärast süsteemipredikaadi kasutamist, s.t. kirjutada atom_concat(S,AsteArv,ArvSõna),S = Sõna.
Veidi erinevalt tuleb käsitleda teistkümneid; kuna mõnikord öeldakse viisteist ja teinekord viisteistkümmend, on vastavad võimalused reeglis ühendatud loogilise või ( ;) abil:

tõlgi(ArvSõna,Loetud,Arv) :-
tähendus(Sõna,Number),
((atom_concat(S,T,ArvSõna),S=Sõna,T=teist);
(atom_concat(S,T,ArvSõna),S=Sõna,T=teistkümmend)),
Arv is Loetud + 10 + Number.
Erireeglit tuleb kasutada ka arvsõnadele, kus sõna "üks" on jäänud ära (tuhat kolmsada kakskümmend):

tõlgi(ArvSõna,Loetud,Arv) :-
aste(Sõna,Aste),
atom_concat(S,ArvSõna1,ArvSõna),S=Sõna,
Loetud1 is Loetud + Aste,
tõlgi(ArvSõna1,Loetud1,Arv).
Ka mitmesõnalistes arvsõnades esinevate tühikute jaoks peab olema reegel:

tõlgi(ArvSõna,Loetud,Arv) :-
atom_concat(T,ArvSõna1,ArvSõna), T = ' ',
!,
tõlgi(ArvSõna1,Loetud,Arv).
Arvsõna interpreteerimisprotsess käivitatakse kahekohalise predikaadiga tõlgi, mille esimeseks argumendiks on interpreteeritav arvsõna, teiseks saadakse selle väärtus; see omakorda käivitab ülalvaadeldud kolmekohalise predikaadi tõlgi. Kuna midagi ei ole veel loetud, on loetud osa väärtus 0:

tõlgi(ArvSõna,Arv) :-
tõlgi(ArvSõna,0,Arv).

Ülesandeid:
1. Tee programm (sõnaliselt esitatud) järgarvude väärtuse leidmiseks (numbriliselt esitatakse järgarv numbri ja talle järgneva punktiga, seega siin ka teine argument on aatom), näiteks tõlgi_järgarv('kahesaja kolmas', '203.').
2. Tee programm, mis teisendab sõnade (aatomid) nimistu üheks aatomiks, kus sõnade esitähed on suurtähed, sõnade vahel (v.a. enne viimast) on komad ja enne viimast sõna - sidesõna "ja", näiteks nimistu [juss,mari,juku] muutuks aatomiks 'Juss, Mari ja Juku'.


Küsimused, probleemid: ©2004 Jaak Henno