A klózok használhatnak állapot változókat
a sorozatokban szereplő közbülső értékek megnevezésének gyorsítására. Vagyis ahol az egyszerű szintaxissal az írnánk, hogy
main(IO0, IO) :-
io.write_string("The answer is ", IO0, IO1),
io.write_int(calculate_answer(...), IO1, IO2),
io.nl(IO3, IO).
ott állapot változókat használva azt irhatjuk, hogy
main(!IO) :-
io.write_string("The answer is ", !IO),
io.write_int(calculate_answer(...), !IO),
io.nl(!IO).
Az állapot változó jelölése !.X
vagy !:X
, amik rendre az X-el jelölt sorozat "aktuális" és a "következő" értékét jelentik. Az !X
argumentum rövidítése a következő két állapotváltozó argumentumnak: !.X, !:X
; vagyis a p(..., !X, ...)
kiértékelése a p(..., !.X, !:X, ...)
kifejezés kiértékelésével történik.
Minden klózon belül megtörténik az állapot változók átalakítása szokásos logikai változók sorozatává. A termekre vonatkozó szintaktikai konverziót a következőkben definiált, fogalmi transform
függvény segítségével írjuk le.
Az átalakítást egyszer alkalmazzuk minden X állapot változóra, mely során új változók friss kerülnek bevezetésre, ezeket ThisX-nek és NextX-nek nevezzük el.
A substitute(Term, X, ThisX, NextX)
kifejezés a Term kifejezés olyan másolatát jelenti, ahol !.X
szabad előfordulásait ThisX-re, és a !:X
előfordulásait NextX-re cseréltük (a szabad előfordulás nem kötött klózfej, lambda kifejezés feje vagy explicit kvantálás által.)
Az állapot változók követik a speciális látahtósági szabályokat. Az X állapot változót explicit be kell vezetni vagy a klóz vagy a lambda kifejezés fejében (ebben az esetben előfordulhat !.X
, vagy !:X
, vagy mindkettő) vagy egy explicit kvantálással (ebben az esetben csak !X
-ként szerepelhet.) Egy lambda vagy egy if-then-else kifejezésben előforduló X állapot változóra a hatáskörében csak a !.X
formában hivatkozhatunk.
Példának okáért a következő cél egy if-then-else kifejezést alkalmaz:
p((if q(!X), r(!X) then A else B), !X)
ez nem érvényes forma, mivel implicit utalást tartalmaz !:X
-ra az if-then-else kifejezés feltételében. Viszont a
p((if some[!X] (q(!X), r(!X)) then A else B), !X)
alak elfogadható, mivel az Xállapotváltozó lokális hatóköre kiterjed az if-then-else kifejezés feltételére és a then-célra, ezért a !:X
előfordulhat bennük.
A lambda kifejezésekben levő állapot változókat illetően három megszorítás van érvényben: először is, !X
nem érvényes függvényeredmény,mivel két argumentumből áll egy helyett; másodszor, !X
nem jelenhet meg paraméter termként egy lambda kifejezés fejében, mivel nincs szintaxis arra, hogy megadjuk a két paraméter módját; harmadszor, !X
nem fodulhat elő egy függvény applikációban argumentumként, mivel ennek nincs értelme az állapot változók és függvények szokásoson interpretációját tekintve.
transform((Head :- Body), X, ThisX, NextX) =
substitute(Head, X, ThisX, NextX) :- transform(Body, X, ThisX, NextX)
transform((Head --> Body), X, ThisX, NextX) =
substitute(Head, X, ThisX, NextX) :- transform(Body, X, ThisX, NextX)
transform((Goal1, Goal2), X, ThisX, NextX) =ahol TmpX friss változó.
transform(Goal1, X, ThisX, TmpX), transform(Goal2, X, TmpX, NextX)
transform((Goal1 ; Goal2), X, ThisX, NextX) =
transform(Goal1, X, ThisX, NextX) ; transform(Goal2, X, ThisX, NextX)
transform((not Goal), X, ThisX, NextX) =a DummyX friss változókra.
not transform(Goal1, X, ThisX, DummyX), NextX = ThisX
transform((if Goal1 then Goal2 else Goal3), X, ThisX, NextX) =a TmpX friss változókra.
if transform(Goal1, X, ThisX, TmpX) then transform(Goal2, X, TmpX, NextX)
else transform(Goal3, X, ThisX, NextX)
transform((Goal1 => Goal2), X, ThisX, NextX) =a TmpX friss változókra.
transform(Goal1, X, ThisX, TmpX) => transform(Goal2, X, TmpX, NextX),
NextX = ThisX
transform((all Vars Goal), X, ThisX, NextX) =a DummyX friss változókra.
all Vars transform(Goal, X, ThisX, DummyX), NextX = ThisX
transform((some Vars Goal), X, ThisX, NextX) =
some Vars transform(Goal, X, ThisX, NextX)
!:X
nem fordul elő a Hívás_vagy_egyesítés kifejezésben, akkortransform(Call_or_Unification, X, ThisX, NextX) =Ha
substitute(Call_or_Unification, X, ThisX, NextX), NextX = ThisX
!:X
előfordul a Hívás_vagy_egyesítés kifejezésben, akkortransform(Call_or_Unification, X, ThisX, NextX) =
substitute(Call_or_Unification, X, ThisX, NextX)
Ez az átalakítás változóegyesítések láncolatainak megjelenését eredményezheti, amik egyébként nem játszanak szerepek a definícióban. Ilyen láncok eltávolításra kerülnek.
A következő kódrészletek az állapotváltozók helyes használatának szintaxisát illusztálják.
main(!IO) :-
io.write_string("The 100th prime is ", !IO),
X = prime(100),
io.write_int(X, !IO),
io.nl(!IO).
foldl2(_, [], !A, !B).
foldl2(P, [X | Xs], !A, !B) :-
P(X, !A, !B),
foldl2(P, Xs, !A, !B).
iterate_while2(P, F, !A, !B) :-
( if P(!.A, !.B) then
F(!A, !B),
iterate_while2(P, F, !A, !B)
else
true
).