Deklaratív programozás - Prolog gyakorlati feladatok
Ez az oldal a korábbi SCH wikiről lett áthozva.
Ha úgy érzed, hogy bármilyen formázási vagy tartalmi probléma van vele, akkor, kérlek, javíts rajta egy rövid szerkesztéssel!
Ha nem tudod, hogyan indulj el, olvasd el a migrálási útmutatót.
Feladat
append(X, _, [a,b,c,d]), X = [_|_], !.
Megoldás
X = [a] ? ; no
Komment
append (A, B, AB).
Ez alapból azt csinálja, hogy A mögé fűzi B-t, és ezt AB-ben adja vissza. Ennek inverz művelete az, ha a kimenetre egy véges listát adsz meg, és a bemenetekhez meg tetszőleges változókat írsz. Ekkor a Prolog az összes lehetséges módon szétbontja az AB listát 2 részre. Ez azt jelenti, hogy
A=[], B=[a,b,c,d];
A=[a], B=[b,c,d];
...
A=[a,b,c,d], B=[];
listákat csinál belőle.
Mivel a klóz nem csak ennyiből áll, hanem van mögötte egy X = [_ | _] is,
csak olyan szétbontás fog megfelelni, ami nem eredményez az első listában
üres listát (tehát A nem []). Ebből az első jó megoldás az A=[a]. Így kerül
X-be X=[a|[]], vagy rövidebben írva X=[a]. Mivel a klóz 3. céljában egy
vágó szerepel (egy ! jel), ezért az összes további megoldás le sem
fog generálódni, hiszen egy helyes megoldás utan leáll a kereséssel.
Feladat
select(1, [2,X,3], L).
Megoldás
X = 1, L=[2,3] ? ; no
Komment
A fenti hívás azt mondja, hogy a [2,X,3] listából szeretnénk elhagyni az 1-es elemet. A select viszont meghiúsul, ha a listának nincs olyan eleme, ami megegyezik az elhagyandóval. Tehát ha azt szeretnénk, hogy a fenti hívás sikerrel fusson le, az X-nek 1-nek kell lennie.
Feladat
number_codes(123, [_|L]), number_codes(X, L).
Megoldás
L = [50,51], X = 23 ? ; no
Komment
number_codes(Szam, Kodok).
A number_codes eljárás a Szam-ot - decimális alakban - stringként értelmezi és a Kodok listában visszaadja az ASCII kódjait. A feladatban L ennek a listának a farkát képviseli, tehát a 2 és 3 számok kódjai vannak benne. A második number_codes hívás épp az előző ellentettjé csinálja, azaz a listában kapott kódokból készült számot adja vissza X-ben. (Érdemes megfigyelni, hogy a number_codes kétirányban is használható. ;) )
Feladat
\+ \+ X = 1, X = 2.
Megoldás
X = 2 ? ; no
Komment
Először elemezzük ki a \+ \+ X = 1 részt.
\+ X = 1 akkor lesz igaz, ha X nem egyesíthető 1-el. Mivel X egy változó, így egyesíthető, tehát \+ X = 1 meghiúsul, \+ \+ X = 1 viszont már igaz lesz (kétszeres tagadás). Fontos tudni a \+ szerkezet viselkedéséről, hogy a \+ X = 1 nem helyettesíti be X értékét, az - jelen esetben - továbbra is egy változó marad. Ezért a következő X = 2 hívás egyesíteni tudja X értékét 2-vel.
Feladat
[A,B] = [x,y,z].
Megoldás
no
Komment
Nagyon egyszerű: az [A,B] egy kételemű lista, [x,y,z] pedig három elemű, ezért nem egyesíthetőek.
Feladat
X = : = 3*4.
Megoldás
! Instantiation error
Komment
Na itt a jó öreg Instantiation Error. :) Az = : = operátorról tudni kell, hogy mindkét oldalán tömör aritmetikai kifejezéseket vár, tehát nem lehet bennük változó. Márpedig X egy változó, ezért Futási hibát (Inst. Error) kapunk.
Feladat
X = 2*4, \+ X = 8.
Megoldás
X = 2*4 ? ; no
Komment
Az X = 2*4 hívás hatására X 2*4-gyel egyesül. (A Prolog egyesítésnél nem számolja ki az aritmetikai kifejezések értékét!) A \+ X = 8 hívás akkor sikerül, ha X nem egyesíthető 8-cal. Mivel X-ben 2*4 van, ami NEM egyesíthető 8-cal, így a hívás sikerrel fut le.
Feladat
X+Y = 2+3*4.
Megoldás
X = 2, Y = 3*4 ? ; no
Komment
Itt az operátorok eltérő prioritására láthatunk példát.
A szemléltetés érdekében alapstruktúra alakra hozva a két oldalt: +(X, Y) = +(2, *(3,4))
Innen már azonnal látszik, hogy X = 2 és Y = 3*4 lesz az egyesítési algoritmus eredménye.
Feladat
% parospoz(+L, ?A): A egy pozitív szám, amely páros indexű % eleme az Lszámlistának. A listaelemeket 1-től % számozzuk.
Megoldás
parospoz([_,A|_], A) :- A > 0. parospoz([_,_|T], A) :- parospoz(T, A).
Komment
Feladat
% szomsz(+L, ?Ossz, ?A, ?B): Az L számlistában A és B % szomszédos elemek, és összegük Ossz.
Megoldás
szomsz([A,B|_],O,A,B):- O is A+B. szomsz([_|Xs],O,A,B):- szomsz(Xs,O,A,B).
Komment
Feladat
% kozep(+L, ?A): A egy olyan eleme az L listának, amely a % bal és jobb szomszédjának számtani közepe.
Megoldás
kozep([X,Y,Z|_],K):- Y=:=(X+Z)/2, K=Y. kozep([_|Zs],K) :- kozep(Zs,K).
Komment
Feladat
% nullpar(+L, ?NL): NL egy olyan kételemű (folytonos) % részlistája L-nek, amelynek összege 0.
Megoldás
nullpar([A,B|Xs],[A,B]):- 0=:=A+B. nullpar([_|Xs],NP):- nullpar(Xs,NP).
Komment
Feladat
% hosszabb(R,H): igaz, ha R hosszabb mint H
Megoldás
hosszabb([_|_],[]). hosszabb([_|T1],[_|T2]) :- hosszabb(T1,T2).
Komment
ETS elfogadta.
Feladat
% rakov(+L0, ?L): L ugyanolyan hosszú, mint az L0 % számlista, és minden eleme 1-gyel nagyobb mint L0 azonos % sorszámú eleme.
Megoldás
rakov([], []). rakov([A|T1],[B|T2]) :- B is A+1, rakov(T1, T2).
Komment
ETS elfogadta.
Feladat
% parospoz(+L, ?A): A egy pozitív szám, amely páros indexű % eleme az L számlistának. A listaelemeket 1-től % számozzuk.
Megoldás
parospoz([_, A | T], P) :- A > 0, P is A. parospoz([_,_|T],A) :- parospoz(T,A).
Komment
ETS elfogadta.
Feladat
% parosneg(+L, -A): A egy negatív szám, amely páros indexű % eleme az L számlistának. A listaelemeket 1-től % számozzuk.
Megoldás
parosneg([_, A | T], P) :- A < 0, P is A. parosneg([_,_|T],A) :- parosneg(T,A).
Komment
ETS elfogadta.
Feladat
% count(+X, +L, ?N): Az L lista elemeként az X kifejezés % pontosan N-szerfordul elő
Megoldás
count(X, [], 0). count(X, [E|L], N) :- ( X = E -> count(X, L, S), N is S + 1 ; count(X, L, N) ).
Komment
ETS elfogadta.