31
SICStus Objects Objektum orientált kiterjesztés a SICStus Prolog nyelvhez Pereszlényi Attila e-mail: [email protected] Az előadás anyaga letölthető: http://www.hszk.bme.hu/~pa310/progs/files/SICStusObjec ts.ppt A példaprogramok letölthetőek: http://www.hszk.bme.hu/~pa310/progs/files/SICStusObjec ts.pl

SICStus Objects

  • Upload
    lynna

  • View
    29

  • Download
    0

Embed Size (px)

DESCRIPTION

SICStus Objects. Objektum orientált kiterjesztés a SICStus Prolog nyelvhez Pereszlényi Attila e-mail: [email protected] Az előadás anyaga letölthető: http://www.hszk.bme.hu/~pa310/progs/files/SICStusObjects.ppt - PowerPoint PPT Presentation

Citation preview

Page 1: SICStus Objects

SICStus Objects

Objektum orientált kiterjesztés a SICStus Prolog nyelvhez

Pereszlényi Attila

e-mail: [email protected] előadás anyaga letölthető:

http://www.hszk.bme.hu/~pa310/progs/files/SICStusObjects.ppt

A példaprogramok letölthetőek: http://www.hszk.bme.hu/~pa310/progs/files/SICStusObjects.pl

Page 2: SICStus Objects

2

A SICStus Objects a prototípusokon alapszik. A prototípus egy objektum, amely a modellezendő világ egy entitása. Felhasználható arra, hogy belőle további objektumokat származtassunk, amelyek öröklik valamely tulajdonságait a prototípusnak, és amelyek maguk is prototípusok lehetnek. A két lehetséges eszköz ennek megvalósítására az öröklés és a delegáció. Egy objektum prolog predikátumok halmaza. A SISCtus Objects ennek alapján a SICStus modul rendszere kiterjesztésének tekinthető, és ez implementációs szinten is igaz. Egy objektum predikátumai lehetnek attribútumok vagy metódusok. Egy objektum lehet statikus vagy dinamikus, lehet definiálva a forrásban vagy létre lehet hozni dinamikusan a program futása során. Metódusok is lehetnek statikusak vagy dinamikusak.

Bevezetés

Page 3: SICStus Objects

3

A könyvtár betöltéséhez az alábbi szükséges:

| ?- use_module(library(objects)).

Ez az alábbi operátorokat (újra)definiálja:

:- op(1200, xfy, [ & ]).

:- op(1198, xfx, [ :- ]).

:- op(1198, fx, [ :- ]).

:- op(550, xfx, [ ::, <: ]).

:- op(550, fx, [ ::, <: ]).

SICStus Objects library

Page 4: SICStus Objects

4

Egy objektumot a következőképpen deklarálhatunk:

objektum-azonosító :: {predikátum-1 &predikátum-2 &

:predikátum-n

}.

Itt az objektum-azonosító egy prolog kifejezés (atom, vagy funktor(V1,…,Vn) alakú, ahol Vi változó), predikátum-i pedig egy metódus vagy attribútum.

Megjegyzés: Minden predikátumra meghívódik az expand_term/2 eljárás, ez előtt pedig a method_expansion/3 kampó eljárás.

Objektum deklaráció

Page 5: SICStus Objects

5

Egy metódus klózait hasonlóan kell deklarálni, mint a Prolog klózokat, lehet szabály, tényállítás, ill. megengedett „catch-all” klózt használni utolsó klózként. A „catch-all” olyan klóz, aminek a feje egy Prolog változó, és minden olyan üzenetre illik, amely nem illik egyetlen előző klózra sem.

Szabály törzsében lévő célsorozat az alábbi normál Prolog vezérlési szerkezet lehet:

:P, :Q Konjunkció

:P; :Q Diszjunkció

! Vágó

\+ Negálás

:P -> :Q:P -> :Q; :Rif(:P, :Q, :R)

If-then-[else]

?A = ?B Egyesítés

Metódus deklaráció 1/4

Page 6: SICStus Objects

6

Szabály törzsében lévő célsorozat lehet még:

:goal A forrás modulban lévő Prolog célsorozat hívása.

m:goal Az m modulban lévő Prolog célsorozat hívása.

goal A Self objektumnak elküldi a goal célsorozatot.

::goal Az objektumban definiált vagy öröklött metódusnak elküldi a goal célsorozatot.

<:goal Az objektumban definiált vagy öröklött metódusnak delegálja a goal célsorozatot.

object::goal object objektumnak elküldi a goal célsorozatot.

object<:goal object objektumnak delegálja a goal célsorozatot.

Metódus deklaráció 2/4

Page 7: SICStus Objects

7

list_object :: {:- :use_module(library(lists), [member/2]) &

append([], L, L) &append([X|L1], L2, [X|L3]) :-

:: append(L1, L2, L3) &

member(X, L) :-:member(X,L) &

length([], 0) &length([_|L], N) :-

:: length(L, N1),:(N is N1+1)

}.

member/2 -t importáljuk …

…majd utána a forrás modulból hívjuk.

Ebben az objektumban definiált metódusra hivatkozunk.

Metódus deklaráció 3/4, példa 1/2

Page 8: SICStus Objects

8

Attribútumok megadása tényállítással:

apt_1 :: {super(apartment) &

street_name(’York’) &street_number(100) &wall_color(white) &floor_surface(wood)

}.

Jobb megoldás attributes használatával:

apt_1 :: {super(apartment) &

attributes([street_name(’York’),street_number(100),wall_color(white),floor_surface(wood)])

}.

Megjegyzés: Az attributes-szal megadott attribútumokat hatékonyan lehet kezelni a get/1 és a set/1 metódusokkal.

Metódus deklaráció 4/4, példa 2/2

Page 9: SICStus Objects

9

Nagy programok írásakor hasznosak lehetnek az újrahasznosítható objektumok. Egy lehetséges megvalósítási technika a generikus objektumok. Ez azt jelenti, hogy paraméterezhető prototípusokat definiálunk, amelyeknek a különböző paraméterekkel ellátott példányait különböző feladatokra lehet használni. Ezt azért lehet megtenni, mert az objektum azonosító összetett kifejezés is lehet. A kifejezésben lévő változók az objektum törzsében hozzáférhetőek. A paraméterezett objektumok azért is fontosak, mert velük elkerülhető az, hogy minden klóznak - ami egy adott kontextusban van - adnunk kelljen plusz változókat, mert a paraméter az objektum törzsén belül egy globális változónak felel meg.

Generikus Objektumok 1/2

Page 10: SICStus Objects

10

Generikus Objektumok 2/2, példarat :: {

(P/Q < R/S) :- :(P*S < Q*R)}.

sort(Type) :: {:- :use_module(library(lists), [append/3]) &

qsort([], []) &qsort([P|L], S) :-

partition(L, P, Small, Large),qsort(Small, S0),qsort(Large, S1),:append(S0, [P|S1], S) &

partition([], _P, [], []) &partition([X|L1], P, Small, Large) :-

( Type :: (X < P) ->Small = [X|Small1], Large = Large1

; Small = Small1, Large = [X|Large1]),

partition(L1, P, Small1, Large1)}.

A rat objektum a racionális számok összehasonlításáért felel.

Az objektum paramétere.

A paraméterben megadott objektummal összehasonlíttatjuk X-et és P-t.

Egy futási példa:

| ?- sort(rat) :: qsort( [23/3, 34/11, 45/17], L).

L = [45/17,34/11,23/3]

Page 11: SICStus Objects

11

Self

A SICStus Objects-ben minden metódus egy objektum kontextusában fut. Ez nem feltétlenül az a statikus objektum, amelyben a metódus deklarálva van. Az aktuális környezeti objektum (Self) arra szolgál, hogy meghatározzuk a hozzáférhető attribútumokat és metódusokat. Az ezt megvalósító mechanizmust dinamikus kötésnek nevezzük. A környezeti objektumhoz hozzáférni a self(S) metódussal lehet, ahol S egyesítődik az objektummal. A a környezeti objektumra hivatkozni lehet még a self konstanssal.

Page 12: SICStus Objects

12

Üzenet küldés és delegáció 1/3

objektum :: üzenet

:: üzenet

Üzenet küldése. Küldéskor az üzenetnek megfelelő metódus a címzett objektum (objektum) kontextusában fut. Ekkor a Self az objektumra állítódik. Ha a címzettet nem írjuk ki, akkor a címzett az az objektum lesz, ahol a célsorozat található.

objektum <: üzenet

<: üzenet

Üzenet delegáció. Delegációkor az üzenetnek megfelelő metódus a delegáló objektum kontextusában fut. Fontos, hogy a delegáció nem változtatja meg a Self-et. Ha a címzettet nem írjuk ki, akkor a címzett az az objektum lesz, ahol a célsorozat található.

Page 13: SICStus Objects

13

Üzenet küldés és delegáció 2/3, pl.1physical_object :: {

volume(50) &density(100) &weight(X) :-

volume(V),density(D),:(X is V*D)

}.

a :: {volume(5) &density(10) &

Method :-physical_object <: Method

}.

b :: {volume(5) &density(10) &

Method :-physical_object :: Method

}.

Minden olyan üzenetre illik, ami nem volume vagy density.

Az üzenetet tovább delegálja.

Az üzenetet továbbküldi.

Egy futási példa:

| ?- a :: weight(X), b :: weight(Y).

X = 50Y = 5000

Page 14: SICStus Objects

14

Üzenet küldés és delegáció 3/3, pl.2Az előző physical_object definícióval ekvivalens:

physical_object :: {volume(50) &density(100) &weight(X) :-

self(S),S::volume(V),S::density(D),:(X is V*D)

}.

Self-nek küldünk üzenetet.

physical_object :: {volume(50) &density(100) &weight(X) :-

self::volume(V),self::density(D),:(X is V*D)

}.

Self-re hivatkozhatunk a self konstanssal.

Page 15: SICStus Objects

15

Öröklődés

Szülő osztályt definiálni a super/2 metódussal lehet az objektum törzsén belül. (super(Super) metódust is lehet használni, ez azonban át fog íródni super(Super, []) alakúra.) A super/2-vel deklarált objektumok lesznek a közvetlen szülei az objektumunknak, ezektől fogja örökölni a metódusokat. Ha egy gyerek objektumban olyan metódust definiálunk, amely valamelyik szülő objektumban már van, akkor a szülő objektumban lévő klózok a gyerek számára láthatatlanok. Ha azt szeretnénk, hogy egy metódus úgy legyen értelmezve, mint a klózai összessége a gyerek objektumban és az egész felette lévő hierarchiában, akkor ezt megtehetjük a szülő objektumnak delegált üzenet segítségével. Ezt unió öröklődésnek nevezzük. A super/2 második argumentuma egy lista, az ebben a listában megadott metódusokat a gyerek osztály nem fogja örökölni. Ezt differenciális öröklődésnek nevezzük.

Page 16: SICStus Objects

16

Öröklődés, példaÁllatok osztályozása:

animal :: {}.

bird :: {super(animal) &

skin(feather) &habitat(tree) &motions(fly)}.

penguin :: {super(bird) &

habitat(land) &motions(walk) &motions(swim) &size(medium)}.

Futási példa:

| ?- penguin :: motions(M).M = walk ;M = swim ;no

(Gyerek metódusa felüldefiniálja a szülőjét.)

| ?- penguin :: skin(S).S = feather ;no

(Gyerek örökli a szülő metódusait.)

Page 17: SICStus Objects

17

Többszörös öröklődés

Több szülő objektumot a super/2 többszöri alkalmazásával adhatunk meg.

Például:

john :: {super(sportsman) &super(professor) &

:}.

Ekkor a szülő objektumok prioritást kapnak abban a sorrendben, ahogy definiálva lettek a super/2-vel. A fenti példában a sportsman dominálja a professort, ami azt jelenti, hogy ha mindkettőben van azonos metódus, akkor a gyerek objektumból a sportsman metódusa fog látszani.

Page 18: SICStus Objects

18

object, super/1 és sub/1

A SICStus Objects-ben létezik egy előre definiált objektum, amit object-nek hívnak, és amiben több hasznos és általános célú metódus van implementálva. Az object szolgáltatásaihoz úgy célszerű hozzáférni, hogy minden objektumot ebből örököltetünk, azaz az objektumok legősibb őse object kell legyen.

Két hasznos object által adott metódus a super/1 és a sub/1, amivel az objektum hierarchiát lehet bejárni. (Ez a super/1 nem ugyanaz, mint öröklődésnél használt, mert az mindig átíródik super/2 alakúra.) A super/1 a Self közvetlen szüleit adja vissza, míg a sub/1 a közvetlen gyerekeit.

Az előző példa esetén:| ?- john :: super(S), S :: sub(john).S = sportsman ;S = professor ;no

Page 19: SICStus Objects

19

A super kulcsszóA super konstans arra használható, hogy adott objektum legnagyobb prioritású szülőjének üzenetet küldjünk vagy delegáljunk. Ezt a következő hívásokkal tehetjük meg:

super :: method, vagysuper <: method

Példa:Tegyük fel, hogy John-nak három id_card-ja van. Az egyik megmondja, hogy John melyik klubban sportol, ez a sportsman-ban van definiálva, a másik megmondja, hogy melyik egyetemen dolgozik, ez a professor-ban van definiálva, a harmadik pedig a személyigazolványa, ami a john-ban van definiálva.

Ha a john-ban szerepel az alábbi:m1(X) :-

super <: id_card(X) &

Akkor kérdezhetjük a következőt: | ?- john :: m1(X). X = johns_club ;Ami visszaadja a legnagyobb prioritású szülő id_card-ját.

Page 20: SICStus Objects

20

Példa unió öröklődésreAdott az előző john osztály a három id_card-dal, és most azt szeretnénk, hogy egy kérdésre visszakapjuk John összes id_card-ját. Ezt a következőképpen tehetjük meg:

Definiáljuk john-ban az alábbi m2/1 metódust:m2(X) :-

(self(S); super(S)),S <: id_card(X) &

Ekkor az alábbi kérdés visszaadja az összes id_card-ot: | ?- john :: m2(X). X = johns_personal_id; X = johns_club ; X = johns_university ;

Vagy felvesszük az alábbi klózt john-ban az id_card-ja után:

id_card(X):-super(S),S <: id_card(X) &

Ekkor az alábbi kérdés adja vissza az összes id_card-ot: | ?- john :: id_card(X). X = johns_personal_id; X = johns_club ; X = johns_university ;

Page 21: SICStus Objects

21

Dinamikus objektumok

Az előzőekben látott objektumoknak futás közben nem lehet megváltoztatni a metódusait. Ezeket az objektumokat statikusaknak nevezzük. Ahhoz hogy a metódusokat meg tudjuk változtatni, az objektumot dinamikusnak kell deklarálni. Ez a dynamic tényállítás objektum törzsébe történő felvételével tehető meg. (Az egyetlen nem megváltoztatható metódus a super/2). Az objektumot az object-ből kell örököltetni, mert az valósítja meg a dynamic-ot.

dynamic_object :: {super(object) &dynamic &:}.

Page 22: SICStus Objects

22

Dinamikus metódusok

Ha azt akarjuk, hogy csak adott F/N funktorú metódusokat lehessen megváltoztatni, akkor megtehetjük, hogy ezeket dinamikusnak deklaráljuk, és az objektum statikus marad.

some_object :: {super(object) &dynamic F/N &:}.

Metódushoz új klózt felvenni, vagy régi klózt eltávolítani az assert/1 és retract/1 metódusokkal lehet, úgy mint a normál SICStus Prolog predikátumok esetében. Használható még az augment/1, aminek a paramétere { sentence-1 & ... & sentence-n } alakú. Ez az összes sentence-i-t felveszi az objektum törzsébe.

Page 23: SICStus Objects

23

Dinamikus metódusok, példa 1/2Könyvtárban lévő könyveknek objektumokat (book) feleltetünk meg, amelyekben tároljuk a könyv címét (title), szerzőjét (author), és a kölcsönzési információkat (history_item(Person, Status, Date), ahol Status borrowed vagy returned). A kölcsönzési információk változtathatók kell legyenek.

Egy tipikus könyv az alábbi lehet:

book_12 :: {super(book) &

title(‘The Art of Prolog’) &authors([‘Leon Sterling’, ‘Ehud Shapiro’]) &

dynamic history_item/3 &

history_item(‘Dan Sahlin’, returned, 92-01-10) &history_item(‘Dan Sahlin’, borrowed, 91-06-10) &:}.

statikus metódusok

dinamikus metódus

Page 24: SICStus Objects

24

Dinamikus metódusok, példa 2/2Írjuk meg a book borrow/1 metódusát, aminek a segítségével a könyvek kikölcsönzését adminisztrálhatjuk! (Feltesszük, hogy a legelső history_item/3 jelzi a legutolsó tranzakciót, és hogy létezik egy date objektumunk, amiből az aktuális dátumot megkaphatjuk.)

borrow(Person) :-history_item(_Person0, Status, _Date0), !,( Status = returned -> date::current(Date), asserta(history_item(Person, borrowed, Date)); :display(‘book not available’), :ttynl) &

Felveszünk egy új tényállítást a többi elé, ami a könyv kikölcsönzött állapotát tárolja.

Page 25: SICStus Objects

25

| ?- c::p(X).no

| ?- b::p(X).X = 3 ? ;X = 1 ? ;X = 2 ? ;no

Dinamikus tulajdonság öröklődéseA gyermek objektumok öröklik a szüleik dinamikus viselkedését is. Tehát a szülőkben definiált dinamikus metódusok megtalálhatóak lesznek a gyermekben is, és a dinamikus viselkedésük is megőrződik.

Példa:

a:: {super(object) &dynamic p/1 &p(1) &p(2)}.

b :: {super(a)}.

c :: {super(a) &dynamic p/1

}.

Futási példa:

| ?- b::p(X).X = 1 ? ;X = 2 ? ;no

Újradeklaráljuk p/1-et dinamikussá. b-ben a dinamikus

viselkedés öröklődött.

Ha egy metódust újradeklaráltunk, akkor a szülőben lévő klózok elvesznek.

| ?- b::asserta(p(3)).yes

Page 26: SICStus Objects

26

Futási idejű objektumdefiníció 1/2Az eddigi módszerekkel nem lehet futás közben létrehozni vagy megváltoztatni az objektum hierarchiát, mert a super/2 nem lehet dinamikus. Ezért az öröklődési viszonyok már fordítási időben rögzülnek. Igény lehet azonban arra, hogy a program futása során hozzuk létre az objektum hierarchiát, amire a SICStus Objects lehetőséget ad. (Ezt is az object valósítja meg.)

Objektum létrehozása futási időben (new/1):

+SomeObject :: new(?NewObject)

+SomeObject :: new(?NewObject,+Supers)

NewObject-et létrehozza, aminek a szülője SomeObject lesz.

NewObject-et létrehozza, aminek a szülei a Supers-ben megadott objektumok lesznek. Supers vagy egy objektum azonosítokból alló lista, vagy egy objektum azonosító – nem örökölendő metódus lista párokból álló lista.

Page 27: SICStus Objects

27

Futási idejű objektumdefiníció 2/2Megjegyzés 1: NewObject lehet atom, változó vagy struktúra, aminek az argumentumai változók.

Megjegyzés 2: mivel new egy üzenet, amit a SomeObject-nek küldünk, ezért értelmes a new(?NewObject) használata, ami NewObject-et úgy hozza létre, hogy Self lesz a szülője.

Megjegyzés 3: A futási időben létrehozott objektumok mindig dinamikusak.

Megjegyzés 4: A metódusokat ugyan úgy lehet létrehozni vagy megváltoztatni, mint a statikus objektumok dinamikus metódusait.

Példa (objektumok létrehozása):

| ?- object :: new(vehicle), vehicle :: new(moving_van), moving_van :: new(truck).Yes

| ?- truck :: super(X), vehicle :: sub(X).X = moving_van ;no

Metódusok felvétele:

| ?- vehicle :: assert(fuel_level([])), vehicle :: assert(oil_level([])), vehicle :: assert(location([])), truck :: assert(capacity([])), truck :: assert(total_weight([])).yes

Page 28: SICStus Objects

28

Hozzáférés vezérelt programozásA hozzáférés vezérelt programozás alapja az, hogy különböző műveleteket elvégzünk, ha adott „hozzáférés operáció” történt. Nézzünk egy példát ennek a megvalósítására! Tegyük fel, hogy ki akarjuk írni azt, hogy „p hozzaveve”, akkor amikor az f objektumhoz hozzáveszünk egy p(X) tényállítást.

f :: {super(object) &

dynamic p/1 &

p(0) &p(1) &

assert(p(X)) :- !, super <: assert(p(X)),:display(‘p hozzaveve’), :ttynl &

assert(M) :-super <: assert(M) &

:}.

Ha nem p(X)-et vesszük hozzá, akkor a kiírás kivételével ugyanaz.

assert-et újradefiniáljuk f-ben. Ekkor az assert régi funkciója elvész f számára.

Ha p(x)-et vesszük hozzá, akkor kell majd kiírni.

A super-ben még megvan az assert régi funkciója, ezért annak delegáljuk az üzenetet, hogy vegye fel p(x)-et. Azért kell delegálni, hogy Self ne változzon meg, és ezért f-ben legyen felvéve p(X).

Page 29: SICStus Objects

29

Példa – állatok osztályozása 1/2animal :: {

super(utility) &

relative_size(S) :-size(Obj_size),super(Obj_prototype),Obj_prototype :: size(Prototype_size),:(S is Obj_size/Prototype_size * 100) &

common(Obj, CObj):-(self(S1); ancestor(S1)),(S2 = Obj; Obj :: ancestor(S2)),:(S1 == S2), !,CObj = S1

}.

object-ből öröklődik, további hasznos metódusokat valósít meg. Itt csak az ancestor/1-et használjuk.

Mekkora vagyok?

Mekkora a szülő osztályom?

Mekkora vagyok én a szülő osztályomhoz képest?

Visszaadja az objektum hierarchiában az első közös elemet.

Az objektum őseit adja vissza a hierarchiában felfelé haladva.

Page 30: SICStus Objects

30

Példa – állatok osztályozása 2/2bird :: {

super(animal) &moving_method(fly) &active_at(daylight)}.

albatross :: {super(bird) &color(black_and_white) &size(115)}.

kiwi :: {super(bird) &moving_method(walk) &active_at(night) &size(40) &color(brown)}.

albert :: {super(albatross) &size(120)}.

ross :: {super(albatross) &size(40)}.

Futási példák:

| ?- ross :: relative_size(R).R = 34.78260869565217 ? ;no

| ?- albert :: common(kiwi, A), kiwi :: common(albert, A).A = bird ? ;no

| ?- animal :: common(ross, A).A = animal ? ;no

Page 31: SICStus Objects

31

Felhasznált irodalom:

SICStus Prolog User’s Manual