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