Következő írásomban magyar nyelven megfogalmazott alapvető számítási műveletek felismerésére és elvégzésére fogjuk megtanítani a számítógépünket. Az összeadás, a kivonás, a szorzás műveletét lesz képes felismerni és megadni az eredményt magyar nyelven. A tanításhoz a szabályalapú megközelítést fogunk használni és a Prolog programozási nyelvet.
Leírás
Maga a program nagyon szűk keretek között fog mozogni. Egytől ezerig fogjak felismerni a magyar nyelvű tőszámneveket[1] és ezeken fogjuk értelmezni az összeadás, a kivonás és a szorzás műveletén. Az osztást a szűk szótár miatt, ami csak a tőszámneveket tartalmazza, ki kellett hagynom az elemzésből. De a szótárbővítéssel és a szóképző szabályokkal a bemutatott analógia alapján könnyen elvégezhetjük sajátkezűleg.
Prolog
Maga az eszköz a Prolog (SWI-Prolog) programozási nyelv lesz. Erről már szóltunk itt a logikai programozással kapcsolatban, de az algoritmusok világában is szóba került. A Prolog lényegét talán egy mondatban is összefoglalhatjuk: amit képes elemezni, azt képes generálni is. Ezt a tulajdonságát fogjuk mi is kihasználni. Nem csak felismerni lesz képes, hogy egy adott karaktersorozat a magyar tőszámnevek része, hanem egy számot képes lesz lefordítani magyar nyelvre. Sőt, az aritmetikai műveletek implementálásával képes lesz műveleteket végezni a magyar nyelvű tőszámnevekkel, és az eredményt is magyarul adja meg. (Különlegességként még megemlíteném, hogy egy-egy számról képes lesz megmutatni, hogy hányféle magyar mondattal lehet előállítani.)
A szótár és a szabályhalmaz
Első feladat előállítani a tőszámnevek szótárát. Ezt két módon lehet. Egy, felsoroljuk az összeset. (Mivel megadtunk egy alsó és felső határt, ezért ez véges idő alatt és gépelési sebességétől függően lehetséges.) A másik módszer, hogy megkeressük a leírandó szótár szabályszerűségeit. A szabályszerűségeinek felismerése és betáplálásával, a szabályok felállításával ráhagyhatjuk a gépre, hogy előállítsa a megadott határok között előállítható összes grammatikus magyar nyelvű tőszámnevet.
Ehhez először a legkisebb, bonthatatlan elemeire kell szednünk a tőszámneveket. Továbbá a szótári elemeket egy kis kiegészítéssel is ellátjuk. A szótári elem mellett annak értékét is feltüntetjük. Ez a számítások elvégzése miatt szükséges és hogy a szóképzés útján előállított újabb tőszámnevekről el tudjuk dönteni, hogy mennyi az értékük.
/* Szótár */ | |
d1(1) --> [egy]. | |
d2(2) --> [kettő]. | |
d3(2) --> [két]. | |
d(3) --> [három]. | |
d(4) --> [négy]. | |
d(5) --> [öt]. | |
d(6) --> [hat]. | |
d(7) --> [hét]. | |
d(8) --> [nyolc]. | |
d(9) --> [kilenc]. | |
t1(10) --> [tíz]. | |
t1(20) --> [húsz]. | |
t(30) --> [harminc]. | |
t(40) --> [negyven]. | |
t(50) --> [ötven]. | |
t(60) --> [hatvan]. | |
t(70) --> [hetven]. | |
t(80) --> [nyolcvan]. | |
t(90) --> [kilencven]. | |
t2(10) --> [tizen]. | |
t2(20) --> [huszon]. | |
sz(100) --> [száz]. | |
e(1000) --> [ezer]. |
Aztán meg kell határoznunk azon szóképző szabályokat, amelyek a szótár elemeit felhasználva, azok kombinálásaival leírják a kívánt, 1-től 1000-ig tartó tőszámnevek tartományát.
/* Szóképző szabályok */ | |
/* | |
* Nemterminálisból terminális szimbólum | |
* 1..99 | |
*/ | |
szam(X) --> d1(X). | |
szam(X) --> d2(X). | |
szam(X) --> d(X). | |
szam(X) --> t1(X). | |
szam(X) --> t(X). | |
szam(X) --> t2(Y),d1(Z), { X is Y + Z }. | |
szam(X) --> t2(Y),d2(Z), { X is Y + Z }. | |
szam(X) --> t2(Y),d(Z), { X is Y + Z }. | |
szam(X) --> t(Y),d1(Z), { X is Y + Z }. | |
szam(X) --> t(Y),d2(Z), { X is Y + Z }. | |
szam(X) --> t(Y),d(Z), { X is Y + Z }. | |
/* Nemterminálisból nemterminális szimbólum */ | |
egytol_szaz(X) --> szam(X). | |
szaztol_ezer(X) --> egytol_szaz(X). | |
szaztol_ezer(X) --> szaz(X). | |
/* | |
* Nemterminálisból terminális | |
* 100...1000 | |
*/ | |
szaz(X) --> sz(X). | |
szaz(X) --> sz(Y),egytol_szaz(Z), { X is Y + Z }. | |
szaz(X) --> d3(Y),sz(Z), { X is Y * Z }. | |
szaz(X) --> d3(Y),sz(Z),egytol_szaz(Q), { X is Y * Z + Q }. | |
szaz(X) --> d(Y),sz(Z), { X is Y * Z }. | |
szaz(X) --> d(Y), sz(Z), egytol_szaz(Q), { X is Y * Z + Q }. | |
szaz(X) --> e(X). | |
/* Kiinduló állapota */ | |
szamok(X) --> szaztol_ezer(X). |
Továbbá fel kell töltenünk azon plusz szabályokkal, amelyek képesek a műveletek felismerni és elvégezni.
/* Aritmetikai szabályok */ | |
osszeadas(X) --> szamok(Y), [meg], szamok(Z), {X is Y + Z}. | |
kivonas(X) --> szamok(Y), [ből], szamok(Z), { X is Y - Z }. | |
szorzas(X) --> szamok(Y), [szer], szamok(Z), { X is Y * Z}. |
Eredmények tesztelése
A kettős pont az új eredmény kérését jelenti. Ha erre 'false' értéket kapunk, akkor nincs több ilyen érték. Ha van, akkor kiírja a következőt.?- szamok(Értek,Magyarul,[]). | |
Értek = 1, | |
Magyarul = [egy] ; | |
Értek = 2, | |
Magyarul = [kettő] ; | |
Értek = 3, | |
Magyarul = [három] | |
?- szamok(123,Magyarul,[]). | |
Magyarul = [száz, huszon, három] ; | |
false. | |
?- szamok(Érték, [három,száz,nyolcvan,kilenc],[]). | |
Érték = 389 ; | |
false. | |
?- osszeadas(Eredmeny,[három,száz,tizen,kilenc,meg,negyven,nyolc],[]). | |
Eredmeny = 367 ; | |
false. | |
?- kivonas(180,Magyarul,[]). | |
Magyarul = [száz, kilencven, ből, tíz] ; | |
Magyarul = [száz, nyolcvan, egy, ből, egy] ; | |
Magyarul = [száz, kilencven, egy, ből, tizen, egy] . | |
?- szorzas(Eredmeny, [négy, szer, hetven, hét],[]). | |
Eredmeny = 308 ; | |
false. |
Hiányosságok
A magánhangzó-harmónia hiánya. A szorzás (-szor/-szer) és a kivonás (-ból/-ból) ragjai nem illeszkednek az első tőszámnévhez. Ez a könnyen orvosolható lenne, de a szabályokat és a szótárt is át kellene alakítani. Mivel ez inkább bemutató jellegű írás, így ettől eltekintettem.
„Kétszer kettő”. Az eset különlegessége úgy foglalható össze, hogy a szorzás első részében helyes a 'két' alak a szó végén. Ezt nem képes kezelni a program. Mivel a számok/3 predikátum nem generálja és nem is ismeri fel tőszámnévként a 'két' alakot. Pedig a szorzás esetében ennek van értelme. (További példa: "Tizenkétszer kettő")
Továbbá a legnyilvánvalóbb hiányosság, a szótár és a szóképző szabályok nem teljesek. Azt viszont megemlíteném, hogy a szótárat két-három elemmel bővítve, a szóképző szabályokat hasonló analógiával bővítve egy öt perc alatt akár a 999 milliót is képes lenne kezelni a program...
Összefoglalás
Ebben az írásban egy szabályalapú nyelvleírásra mutattam példát. A magyar nyelv egy részhalmazát adtuk meg. Ez nem a teljes tőszámnevek halmaz, annak csak részhalmaza. De példát láthattunk arra, hogy a szóképző szabályokat milyen formában lehet megfogalmazni és a Prolog segítségével tesztelni, kipróbálni.
[1] A magyar tőszámnevek szabályalapú generálásának példáját Szécsényi Tibor: Nyelvtechnológia: a nyelv és a számítógép című szemináriumáról származik (Szegedi Tudományegyetem, 2009). Ezt a példát bővítettem ki azzal, hogy képes legyen ne csak felismerni, hanem műveletek is végezni magyar nyelven.
A teljes forráskód elérhető a Számítógépes Nyelvészet Github tárolójából.
Nincsenek megjegyzések:
Megjegyzés küldése