is_list(Parents),
is_list(Parts),
\+ wrapped_def_class(ClassName, Parents, Parts),
+
+ %% Se fallisce la definizione della classe
+ %% elimina le informazioni residue dalla base di conoscenza
retractall(is_class(ClassName)),
retractall(is_class(ClassName, _)),
retractall(is_child_of(_, ClassName)),
*** Implementazione
#+begin_src prolog :tangle oop.pl
make(InstanceName, ClassName) :-
- var(InstanceName),
- nonvar(ClassName),
- is_class(ClassName),
- !,
- search_instance(InstanceName, ClassName, []).
+ make(InstanceName, ClassName, []).
-make(InstanceName, ClassName) :-
- atom(InstanceName),
+make(InstanceName, ClassName, Fields) :-
+ var(InstanceName),
nonvar(ClassName),
is_class(ClassName),
!,
- make(InstanceName, ClassName, []).
+ search_instance(InstanceName, ClassName, Fields).
make(InstanceName, ClassName, Fields) :-
+ atom(InstanceName),
nonvar(InstanceName),
+ is_class(ClassName),
wrapped_make(InstanceName, ClassName, Fields),
!.
make(InstanceName, ClassName, Fields) :-
+ atom(InstanceName),
nonvar(InstanceName),
+ is_class(ClassName),
\+ wrapped_make(InstanceName, ClassName, Fields),
- !,
+
+ %% Se fallisce la definizione dell'instance
+ %% elimina le informazioni residue dalla base di conoscenza
retractall(is_instance(InstanceName)),
retractall(is_instance(InstanceName, _)),
retractall(field(InstanceName, _, _)),
fail().
-
-make(InstanceName, ClassName, Fields) :-
- var(InstanceName),
- search_instance(InstanceName, ClassName, Fields).
#+end_src
*** Esempio pratico
make(Instance, foobar). %% Instance = fb.
make(Instance, bar, [bar = "69"]). %% Instance = b; false.
#+end_src
+
** field
*** Definizione
Estrae il valore di una classe da un campo
fieldx(fb, [foo,bar,foobar], Result).
#+end_src
+** inst
+*** Definizione
+Dato un oggetto che rappresenta un'istanza restituisce il nome dell'istanza.
+Si nella nostra implementazione è banale perchè l'oggetto che rappresenta l'istanza è il nome dell'istanza.
+
+*** Implementazione
+#+begin_src prolog :tangle oop.pl
+inst(InstanceName, InstanceName).
+#+end_src
+
+*** Esempio pratico
+#+begin_src prolog
+inst(f, f). %% true.
+inst(b, b). %% true.
+inst(X, fb). %% X = fb.
+inst(fb, root). %% false.
+#+end_src
+
* Predicati helper
** Predicati dinamici
Predicati usati con `assert` guarda dove vengono usati e scrivi 2 righe.
is_class(ClassName),
is_member(field(Name, _, _), ClassName),
!,
+
+ %% Se il field da aggiungere è anche un field di una superclass
+ %% allora rimuovilo della base di conoscenza
retractall(is_member(field(Name, _, _), ClassName)),
+
+ %% e sostituiscilo con il field della classe stessa
asserta(is_member((field(Name, Value, nil)), ClassName)),
add_part(ClassName, OtherParts).
is_class(ClassName),
\+ is_member(field(Name, _, _), ClassName),
!,
+
+ %% Se il field non è anche un field di una superclass
+ %% allora di che è un field di questa classe
asserta(is_member((field(Name, Value, nil)), ClassName)),
add_part(ClassName, OtherParts).
#+end_src
is_class(ClassName),
is_member(field(Name, _, _), ClassName),
!,
+
+ %% Se il field da aggiungere è anche un field di una superclass
+ %% allora rimuovilo della base di conoscenza
retractall(is_member(field(Name, _, _), ClassName)),
+
+ %% Controlla che il valore del field sia del tipo del field
type_check(Type, Value),
+
+ %% e sostituiscilo con il field della classe stessa
asserta(is_member(field(Name, Value, Type), ClassName)),
add_part(ClassName, OtherParts).
is_class(ClassName),
\+ is_member(field(Name, _, _), ClassName),
!,
- retractall(is_member(field(Name, _, _), ClassName)),
+
+ %% Se il field non è anche un field di una superclass
+ %% controlla che il valore del field sia del tipo del field
type_check(Type, Value),
+ %% e di che è un field di questa classe
asserta(is_member(field(Name, Value, Type), ClassName)),
add_part(ClassName, OtherParts).
#+end_src
is_list(ArgList),
is_class(ClassName),
asserta(is_member(method(Name, ArgList, Body), ClassName)),
+
+ %% Ricava il termine composto che rappresenta la testa del predicato
Head =.. [Name, InstanceName | ArgList],
!,
+
replace(this, InstanceName, Body, NewBody),
asserta(Head :- (is_instance(InstanceName, ClassName), NewBody, !)),
add_part(ClassName, OtherParts).
set_superclass_fields(InstanceName,
ClassName,
[[Name, Value, Type] | OtherFields]) :-
+ %% Controlla che il valore sia del tipo corretto
type_check(Type, Value),
+
assertz(field(InstanceName, Name, Value)),
set_superclass_fields(InstanceName, ClassName, OtherFields).
#+end_src
set_fields(InstanceName,
ClassName,
[=(Name, Value) | OtherFields]) :-
+ %% Controlla che `Name` sia un field dell'istanza
field(InstanceName, Name, OldValue),
+ %% ed un membro della classe
is_member(field(Name, _Value, Type), ClassName),
+
+ %% Controlla che il nuovo valore sia del tipo corretto
type_check(Type, Value),
- retractall(field(InstanceName, Name, OldValue)),
!,
+
+ %% Rimuove della base di conoscenza il vecchio field
+ retractall(field(InstanceName, Name, OldValue)),
+ %% e lo aggiorna con il nuovo valore
asserta(field(InstanceName, Name, Value)),
+
set_fields(InstanceName, ClassName, OtherFields).
+%% Se arriva a questo caso si è verificato un errore
+%% e deve eliminare le informazioni residue
+%% della creazione dell'istanza
set_fields(InstanceName, _ClassName, _Fields) :-
retractall(is_instance(InstanceName)),
retractall(is_instance(InstanceName, _)),
retractall(field(InstanceName, _, _)),
- !,
fail().
#+end_src
-** Sostituzione di termine
+** Sostituzione del termine `this`
Magia nera chiedi a Mirko.
#+begin_src prolog :tangle oop.pl
-replace(Subterm0, Subterm, Term0, Term) :-
- Term0 == Subterm0,
- !,
- Term = Subterm.
-replace(_Subterm0, _Subterm, Term0, Term) :-
- var(Term0),
- !,
- Term = Term0.
-replace(Subterm0, Subterm, Term0, Term) :-
- Term0 =.. [F | Args0],
- maplist(replace(Subterm0,Subterm), Args0, Args),
- Term =.. [F | Args].
+replace(OldTerm, NewTerm, Body, NewTerm) :- Body == OldTerm, !.
+replace(_OldTerm, _NewTerm, Body, Body) :- var(Body), !.
+replace(OldTerm, NewTerm, Body, Result) :-
+ Body =.. [Funct | BodyFunctArgs],
+
+ %% Chiama ricorsivamente `replace` sugli argomenti di `Body`
+ maplist(replace(OldTerm,NewTerm), BodyFunctArgs, NewFunctArgs),
+
+ %% Ricostruisci il termine composto con:
+ %% - stesso funtore di `Body`
+ %% - argomenti a cui è stata applicata la `replace`
+ Result =.. [Funct | NewFunctArgs].
#+end_src
** Controllo dei tipi
asserta(is_child_of(Parent, ClassName)),
def_class(ClassName, OtherParents),
+ %% Trova tutti i field/method del genitore
+ %% e aggiungili alla classe figlio
findall(Part,
is_member(Part, Parent),
ParentParts),
#+begin_src prolog :tangle oop.pl
wrapped_make(InstanceName, ClassName, Fields) :-
is_list(Fields),
- !,
- instanciate_superclass(InstanceName, ClassName),
- set_fields(InstanceName, ClassName, Fields).
-#+end_src
-
-*** Assegnamento dei valori ereditati dalla superclass all'istanza
-#+begin_src prolog :tangle oop.pl
-instanciate_superclass(InstanceName, ClassName) :-
atom(InstanceName),
nonvar(ClassName),
is_class(ClassName),
\+ is_instance(InstanceName),
- !,
+
asserta(is_instance(InstanceName)),
asserta(is_instance(InstanceName, ClassName)),
+ instanciate_superclass(InstanceName, ClassName),
+ set_fields(InstanceName, ClassName, Fields).
+#+end_src
+
+*** Assegnamento dei valori ereditati dalla superclass all'istanza
+#+begin_src prolog :tangle oop.pl
+instanciate_superclass(InstanceName, ClassName) :-
+ %% Trova tutti i field della classe da istanziare
+ %% e raggruppali in terne (nome, valore, tipo)
findall([Name, Value, Type],
is_member(field(Name, Value, Type), ClassName),
Fields),
+
+ %% Dì per ogni field che è `field` dell'instance `InstanceName`
set_superclass_fields(InstanceName, ClassName, Fields).
#+end_src
is_list(Parents),
is_list(Parts),
\+ wrapped_def_class(ClassName, Parents, Parts),
+
+ %% Se fallisce la definizione della classe
+ %% elimina le informazioni residue dalla base di conoscenza
retractall(is_class(ClassName)),
retractall(is_class(ClassName, _)),
retractall(is_child_of(_, ClassName)),
fail().
make(InstanceName, ClassName) :-
- var(InstanceName),
- nonvar(ClassName),
- is_class(ClassName),
- !,
- search_instance(InstanceName, ClassName, []).
+ make(InstanceName, ClassName, []).
-make(InstanceName, ClassName) :-
- atom(InstanceName),
+make(InstanceName, ClassName, Fields) :-
+ var(InstanceName),
nonvar(ClassName),
is_class(ClassName),
!,
- make(InstanceName, ClassName, []).
+ search_instance(InstanceName, ClassName, Fields).
make(InstanceName, ClassName, Fields) :-
+ atom(InstanceName),
nonvar(InstanceName),
+ is_class(ClassName),
wrapped_make(InstanceName, ClassName, Fields),
!.
make(InstanceName, ClassName, Fields) :-
+ atom(InstanceName),
nonvar(InstanceName),
+ is_class(ClassName),
\+ wrapped_make(InstanceName, ClassName, Fields),
- !,
+
+ %% Se fallisce la definizione dell'instance
+ %% elimina le informazioni residue dalla base di conoscenza
retractall(is_instance(InstanceName)),
retractall(is_instance(InstanceName, _)),
retractall(field(InstanceName, _, _)),
fail().
-make(InstanceName, ClassName, Fields) :-
- var(InstanceName),
- search_instance(InstanceName, ClassName, Fields).
-
:- dynamic field/3.
fieldx(Instance, [FieldName], Res) :-
field(Instance, FieldName, _Value),
fieldx(Instance, Others, Res).
+inst(InstanceName, InstanceName).
+
:- dynamic is_class/1.
:- dynamic is_child_of/2.
:- dynamic is_member/2.
:- dynamic is_instance/2.
add_part(ClassName, []) :- is_class(ClassName), !.
+
add_part(ClassName, [field(Name, Value) | OtherParts]) :-
is_class(ClassName),
is_member(field(Name, _, _), ClassName),
!,
+
+ %% Se il field da aggiungere è anche un field di una superclass
+ %% allora rimuovilo della base di conoscenza
retractall(is_member(field(Name, _, _), ClassName)),
+
+ %% e sostituiscilo con il field della classe stessa
asserta(is_member((field(Name, Value, nil)), ClassName)),
add_part(ClassName, OtherParts).
is_class(ClassName),
\+ is_member(field(Name, _, _), ClassName),
!,
+
+ %% Se il field non è anche un field di una superclass
+ %% allora di che è un field di questa classe
asserta(is_member((field(Name, Value, nil)), ClassName)),
add_part(ClassName, OtherParts).
is_class(ClassName),
is_member(field(Name, _, _), ClassName),
!,
+
+ %% Se il field da aggiungere è anche un field di una superclass
+ %% allora rimuovilo della base di conoscenza
retractall(is_member(field(Name, _, _), ClassName)),
+
+ %% Controlla che il valore del field sia del tipo del field
type_check(Type, Value),
+
+ %% e sostituiscilo con il field della classe stessa
asserta(is_member(field(Name, Value, Type), ClassName)),
add_part(ClassName, OtherParts).
is_class(ClassName),
\+ is_member(field(Name, _, _), ClassName),
!,
- retractall(is_member(field(Name, _, _), ClassName)),
+
+ %% Se il field non è anche un field di una superclass
+ %% controlla che il valore del field sia del tipo del field
type_check(Type, Value),
+ %% e di che è un field di questa classe
asserta(is_member(field(Name, Value, Type), ClassName)),
add_part(ClassName, OtherParts).
is_list(ArgList),
is_class(ClassName),
asserta(is_member(method(Name, ArgList, Body), ClassName)),
+
+ %% Ricava il termine composto che rappresenta la testa del predicato
Head =.. [Name, InstanceName | ArgList],
!,
- replace(this,InstanceName,Body,NewBody),
+
+ replace(this, InstanceName, Body, NewBody),
asserta(Head :- (is_instance(InstanceName, ClassName), NewBody, !)),
add_part(ClassName, OtherParts).
set_superclass_fields(InstanceName,
ClassName,
[[Name, Value, Type] | OtherFields]) :-
+ %% Controlla che il valore sia del tipo corretto
type_check(Type, Value),
+
assertz(field(InstanceName, Name, Value)),
set_superclass_fields(InstanceName, ClassName, OtherFields).
set_fields(InstanceName,
ClassName,
[=(Name, Value) | OtherFields]) :-
+ %% Controlla che `Name` sia un field dell'istanza
field(InstanceName, Name, OldValue),
+ %% ed un membro della classe
is_member(field(Name, _Value, Type), ClassName),
+
+ %% Controlla che il nuovo valore sia del tipo corretto
type_check(Type, Value),
- retractall(field(InstanceName, Name, OldValue)),
!,
+
+ %% Rimuove della base di conoscenza il vecchio field
+ retractall(field(InstanceName, Name, OldValue)),
+ %% e lo aggiorna con il nuovo valore
asserta(field(InstanceName, Name, Value)),
+
set_fields(InstanceName, ClassName, OtherFields).
+%% Se arriva a questo caso si è verificato un errore
+%% e deve eliminare le informazioni residue
+%% della creazione dell'istanza
set_fields(InstanceName, _ClassName, _Fields) :-
retractall(is_instance(InstanceName)),
retractall(is_instance(InstanceName, _)),
retractall(field(InstanceName, _, _)),
- !,
fail().
-replace(Subterm0, Subterm, Term0, Term) :-
- Term0 == Subterm0,
- !,
- Term = Subterm.
-replace(_Subterm0, _Subterm, Term0, Term) :-
- var(Term0),
- !,
- Term = Term0.
-replace(Subterm0, Subterm, Term0, Term) :-
- Term0 =.. [F | Args0],
- maplist(replace(Subterm0,Subterm), Args0, Args),
- Term =.. [F | Args].
+replace(OldTerm, NewTerm, Body, NewTerm) :- Body == OldTerm, !.
+replace(_OldTerm, _NewTerm, Body, Body) :- var(Body), !.
+replace(OldTerm, NewTerm, Body, Result) :-
+ Body =.. [Funct | BodyFunctArgs],
+
+ %% Chiama ricorsivamente `replace` sugli argomenti di `Body`
+ maplist(replace(OldTerm,NewTerm), BodyFunctArgs, NewFunctArgs),
+
+ %% Ricostruisci il termine composto con:
+ %% - stesso funtore di `Body`
+ %% - argomenti a cui è stata applicata la `replace`
+ Result =.. [Funct | NewFunctArgs].
type_check(_X, nil) :- !.
type_check(nil, _X) :- !.
asserta(is_child_of(Parent, ClassName)),
def_class(ClassName, OtherParents),
+ %% Trova tutti i field/method del genitore
+ %% e aggiungili alla classe figlio
findall(Part,
is_member(Part, Parent),
ParentParts),
wrapped_make(InstanceName, ClassName, Fields) :-
is_list(Fields),
- !,
- instanciate_superclass(InstanceName, ClassName),
- set_fields(InstanceName, ClassName, Fields).
-
-instanciate_superclass(InstanceName, ClassName) :-
atom(InstanceName),
nonvar(ClassName),
is_class(ClassName),
\+ is_instance(InstanceName),
- !,
+
asserta(is_instance(InstanceName)),
asserta(is_instance(InstanceName, ClassName)),
+ instanciate_superclass(InstanceName, ClassName),
+ set_fields(InstanceName, ClassName, Fields).
+
+instanciate_superclass(InstanceName, ClassName) :-
+ %% Trova tutti i field della classe da istanziare
+ %% e raggruppali in terne (nome, valore, tipo)
findall([Name, Value, Type],
is_member(field(Name, Value, Type), ClassName),
Fields),
+
+ %% Dì per ogni field che è `field` dell'instance `InstanceName`
set_superclass_fields(InstanceName, ClassName, Fields).
search_instance(InstanceName, ClassName, [=(Field,Value) | Other]) :-