2015-01-26 21 views
8

Ho letto da qualche parte che è possibile pensare a moduli come oggetti in Prolog. Sto cercando di capire come funziona, e se è un buon modo per codificare.Programmazione orientata agli oggetti in SWI-Prolog

Se ho due file, uno definisce un cane di classe e poi un altro che usa questa classe per creare due oggetti cane.

:- module(dog, 
     [ create_dog/4,bark/1 ]). 

create_dog(Name,Age,Type,Dog):- 
    Dog = dog(name(Name),age(Age),type(Type)). 

bark(Dog):- 
    Dog = dog(name(_Name),age(_Age),type(Type)), 
    Type = bassethound, 
    woof. 
bark(Dog):- 
    Dog = dog(name(_Name),age(_Age),type(Type)), 
    Type \= bassethound, 
    ruff. 

woof:-format("woof~n"). 

ruff:-format("ruff~n"). 

secondo file

use_module(library(dog)). 

run:- 
    dog:create_dog('fred',5,bassethound,Dog), 
    forall(between(1,5,_X), 
     dog:bark(Dog) 
    ), 
    dog:create_dog('fido',6,bloodhound,Dog2), 
    dog:bark(Dog2). 

Questo rende un cane oggetto cane che è un basset hound e la rende abbaiare 5 volte, ho poi fare un altro oggetto cane Dog2 che è un segugio e rendere questo anche abbaiare. Capisco che in oop hai oggetti con comportamenti e stati. Quindi ora ho due oggetti con comportamenti diversi basati sui loro stati ma al momento sto memorizzando lo stato degli oggetti nelle variabili Dog dove possono essere visti dal codice nel programma principale. C'è un modo per nascondere lo stato degli oggetti per avere variabili private? Ad esempio, potrei avere un modo di memorizzare lo stato has_barked per ogni oggetto dog, che sarebbe vero se ha abbaiato prima nel programma e falso in caso contrario, quindi modificare il comportamento di bark/1 in base a ciò.

Inoltre, come gestiresti i metodi di ereditarietà e di sovrascrittura, ecc.? Qualsiasi puntatore alle letture accolto favorevolmente. Grazie.

+0

Se non è la risposta che vuoi, proverò a scriverne una più lunga, ma ... penso che tu stia cercando di usare Prolog per gli scopi sbagliati. È un motore logico, non un linguaggio OOP. Il problema sarebbe risolto molto più semplicemente in un linguaggio imperativo/OOP come Python o Java. – Tom

+0

Sto solo sperimentando. Questo è solo un esempio banale, ho un sacco di codice prolog e mi chiedo se usare uno stile combinato di oop e logica sarà un buon modo di fare le cose o no .. felice di sentire i tuoi pensieri, capisco come programmare in Java e python quindi ho familiarità con lo standard oop ma non oop in prolog. – user27815

+0

Penso che l'importante considerazione da notare è che l'OOP è un paradigma, e lo è anche la programmazione logica. In Prolog, non penso che si mescolino particolarmente bene. Se vuoi _ per unire le due discipline, considera un pacchetto come questo: https://code.google.com/p/pyswip/ – Tom

risposta

7

Solo un esempio di una delle possibili reimplementazioni del codice di esempio in Logtalk. Utilizza i prototipi per semplicità, ma illustra ancora alcuni concetti chiave, tra cui ereditarietà, definizioni dei predicati predefiniti, oggetti statici e dinamici e oggetti parametrici.

% a generic dog 
:- object(dog). 

    :- public([ 
     create_dog/3, bark/0, name/1, age/1 
    ]). 

    create_dog(Name, Age, Dog) :- 
     self(Type), 
     create_object(Dog, [extends(Type)], [], [name(Name),age(Age)]). 

    % default definition for all dogs 
    bark :- 
     write(ruff), nl. 

:- end_object. 


:- object(bassethound, 
    extends(dog)). 

    % bark different 
    bark :- 
     write(woof), nl. 

:- end_object. 


:- object(bloodhound, 
    extends(dog)). 

:- end_object. 


% support representing dogs as plain database facts using a parametric object 
:- object(dog(_Name,_Age,_Type), 
    extends(dog)). 

    name(Name) :- 
     parameter(1, Name). 

    age(Age) :- 
     parameter(2, Age). 

    bark :- 
     parameter(3, Type), 
     [Type::bark]. 

:- end_object. 


% a couple of (static) dogs as parametric object proxies 
dog(fred, 5, bassethound). 
dog(fido, 6, bloodhound). 


% another static object 
:- object(frisbee, 
    extends(bloodhound)). 

    name(frisbee). 
    age(1). 

:- end_object. 

Alcune query di esempio:

$ swilgt 
... 
?- {dogs}. 
% [ /Users/foo/dogs.lgt loaded ] 
% (0 warnings) 
true. 

?- bassethound::bark. 
woof 
true. 

?- bloodhound::bark. 
ruff 
true. 

?- bassethound::create_dog(boss, 2, Dog). 
Dog = o1. 

?- o1::bark. 
woof 
true. 

?- {dog(Name, Age, Type)}::bark. 
woof 
Name = fred, 
Age = 5, 
Type = bassethound ; 
ruff 
Name = fido, 
Age = 6, 
Type = bloodhound. 

?- dog(ghost, 78, bloodhound)::(bark, age(Age)). 
ruff 
Age = 78. 

?- forall(between(1,5,_X), {dog(fred,_,_)}::bark). 
woof 
woof 
woof 
woof 
woof 
true. 

alcune note. ::/2 è il messaggio che invia il costrutto di controllo. L'obiettivo {Object}::Message dimostra semplicemente Object utilizzando il semplice database Prolog e quindi invia il messaggio Message al risultato. L'obiettivo [Object::Message]delegati un messaggio a un oggetto mantenendo il mittente originale.

2

Dai un'occhiata allo logtalk. È una specie di estensione orientata agli oggetti di Prolog.

http://logtalk.org/

+1

Grazie, ma sono principalmente interessato nell'uso di swi prolog. – user27815

+1

Poiché questo suggerisce solo un collegamento, dovrebbe essere un commento, non una risposta. – lurker

+2

@ user27815 Logtalk utilizza/richiede un sistema Prolog come compilatore di backend. SWI-Prolog è uno dei sistemi completamente supportati. –

3

Logtalk è effettivamente l'oggetto di primo piano orientato Prolog oggi disponibili. Paulo lo ha reso disponibile come pack, quindi l'installazione dovrebbe essere molto semplice.

I moduli non sono realmente appropriati per l'orientamento dell'oggetto. Sono più simili ai namespace, ma senza nidificazione. Inoltre, lo standard ISO è un po 'polemico.

SWI-Prolog v7 ha introdotto dicts, un'estensione che gestisce almeno un problema storico della lingua e rende disponibili "campi" per nome e una sintassi per "metodi". Ma ancora, nessuna eredità ...

modificare

Ho aggiunto here un piccolo esempio di orientamento agli oggetti in SWI-Prolog. È un'evoluzione del mio test application sulla creazione di alberi genealogici.

Confrontando i sorgenti di genealogy.pl, puoi apprezzare come la versione più recente utilizza lo specificatore del modulo, anziché la direttiva: - multifile, e quindi può lavorare con più alberi.

Si può vedere, il modulo di chiamata è tramandato il codice di costruzione grafico, e hanno predicati opzionali o obbligatori, che viene chiamato per titolo di modulo:

make_rank(M, RPs, Rp-P) :- 
    findall(G, M:parent_child(P, G), Gs), 
    maplist(generated(M, Rp, RPs), Gs). 

predicati opzionali devono essere chiamati come

... 
catch(M:female(P),_,fail) -> C = red 
... 

noti che predicati sono non esportati dai moduli applicativi. Esportandoli, AFAIK, interrompe l'orientamento dell'oggetto.

==========

Un'altra, forse più banale, esempio di orientamento oggetto, è il modulo pqGraphviz_emu, dove predisposto una semplice sostituzione mente di oggetti livello di sistema.

Spiego: pqGraphviz è un piccolo strato - scritto in Qt - su libreria Graphviz. Graphviz - anche se in C - ha un'interfaccia orientata agli oggetti. Infatti, l'API consente di creare oggetti rilevanti (grafici, nodi, collegamenti) e quindi assegnare loro degli attributi. Il mio livello tenta di mantenere l'API più simile all'originale. Per esempio, Graphviz crea un nodo con

Agnode_t* agnode(Agraph_t*,char*,int); 

poi ho scritto con l'interfaccia

PREDICATE(agnode, 4) { 
    if (Agnode_t* N = agnode(graph(PL_A1), CP(PL_A2), PL_A3)) 
     return PL_A4 = N; 
    return false; 
} 

ci scambiamo i puntatori C++, e ho messa a punto l'impianto metatipo Qt per gestire la digitazione ... ma dal momento che l'interfaccia è piuttosto basso livello, di solito hanno un piccolo strato intermedio che espone una visione più applicativo, ed è questa interfaccia di livello medio che viene chiamato da genealogy.pl:

make_node(G, Id, Np) :- 
    make_node(G, Id, [], Np). 
make_node(G, Id, As, Np) :- 
    empty(node, N0), 
    term_to_atom(Id, IdW), 
    N = N0.put(id, IdW), 
    alloc_new(N, Np), 
    set_attrs(Np, As), 
    dladd(G, nodes, Np). 

In questo frammento di codice, è possibile vedere un esempio di dicts del SWI-Prolog v7: schema di assegnazione

... 
N = N0.put(id, IdW), 
... 

La memoria è gestita in allocator.pl.

+0

Per i principianti, l'installazione di Logtalk tramite gli installatori forniti (disponibili per la maggior parte dei sistemi operativi) offre un'esperienza utente migliore. Il pacchetto rende l'installazione molto semplice, ma nasconde anche la directory di installazione in cui si trovano documenti, esempi, strumenti, ecc. (Vedere la descrizione del pacchetto). –

4

I moduli Prolog possono essere interpretati banalmente come oggetti (in particolare, come prototipi). I moduli Prolog possono essere creati dinamicamente, avere un nome che può essere considerato come la loro identità (poiché deve essere univoco in una sessione in esecuzione poiché lo spazio dei nomi del modulo è piatto) e può avere uno stato dinamico (usando i predicati dinamici locali al modulo). Nella maggior parte dei sistemi, tuttavia, forniscono un incapsulamento debole, nel senso che di solito è possibile chiamare qualsiasi predicato di modulo usando una qualifica esplicita (detto, almeno un sistema, ECLiPSe, consente di bloccare un modulo per impedire l'interruzione dell'incapsulazione in questo modo). Non c'è nemmeno il supporto per separare l'interfaccia dall'implementazione o avere più implementazioni della stessa interfaccia (puoi in qualche modo modificarla, a seconda del sistema del modulo Prolog, ma non è carina).

Logtalk, come menzionato in altre risposte, è un'estensione orientata agli oggetti altamente portatile a Prolog che supporta la maggior parte dei sistemi, incluso SWI-Prolog. Gli oggetti Logtalk includono moduli Prolog, sia dal punto di vista concettuale sia da quello pratico. Il compilatore Logtalk supporta un nucleo comune delle funzionalità del modulo. Puoi usarlo, ad es. scrivere il codice del modulo nelle implementazioni Prolog senza un sistema di moduli. Logtalk può compilare moduli come oggetti e supporta chiamate bidirezionali tra oggetti e moduli.

Si noti che gli oggetti in Programmazione logica sono meglio visti come un codice di incapsulamento e meccanismo di riutilizzo del codice. Proprio come i moduli. I concetti OO possono essere (e sono stati) applicati con successo in altri paradigmi di programmazione, compresi quelli funzionali e logici. Ma ciò non significa necessariamente portare avanti concetti imperativi/procedurali. Come esempio, le relazioni tra un un'istanza e la sua classe o tra prototipo come suo genitore possono essere interpretati come specificando un modello di riutilizzo del codice invece di essere visto da un punto-dinamica/stato di vista (infatti, nei linguaggi OOP derivati ​​da linguaggi imperativi/procedurali, un'istanza è poco più di una struttura di dati dinamica glorificata la cui specifica è distribuita tra la sua classe e le sue superclassi di classe).

Considerando il codice di esempio, è possibile ricodificarlo facilmente in Logtalk vicino alla propria formulazione, ma anche in altri modi, il più interessante di essi non fa uso di funzionalità dinamiche. Lo stato di memorizzazione (come in stato dinamico) è talvolta necessario e potrebbe anche essere la soluzione migliore per problemi particolari (Prolog ha predicati dinamici per una ragione!) Ma dovrebbe essere usato con cautela e solo quando veramente necessario. Usando Logtalk non cambia (o intende cambiare) quello.

Suggerisco di esaminare l'ampia documentazione Logtalk ei suoi numerosi esempi di programmazione. Lì troverai come ad es. separare nettamente l'interfaccia dall'implementazione, come utilizzare la composizione, l'ereditarietà, specializzare o ignorare i predicati ereditati, ecc.

+1

Alcuni anni fa ho cercato di piegare l'implementazione del "modulo dinamico" in qualcosa di pratico, seguendo [la documentazione] (http://www.swi-prolog.org/pldoc/man?section=dynamic-modules), ma Ho avuto una brutta esperienza, quindi ho preferito non consigliare l'OP a questa possibilità. – CapelliC

2

il sistema PCE in SWI-Prolog è anche un'opzione per OOP in Prolog. Di solito è associato a xpce, il sistema GUI, ma in realtà è un sistema OO basato su una classe generica.

0

Al giorno d'oggi, il prologo SWI ha dicts che interagiscono con i moduli in un modo piacevole. Vedere The SWI prolog manual page on dicts, in particolare la sezione 5.4.1.1: Funzioni definite dall'utente in dict.

Ciò consente di definire cose che sembrano esattamente come metodi, fino a valori di ritorno (inusuali ma molto utili in Prolog).

Diversamente da quanto discusso in alcune delle altre risposte, personalmente trovo che i paradigmi di programmazione logica e OOP siano ortogonali l'uno con l'altro: sicuramente non fa male essere in grado di strutturare il codice logico usando la modularità OOP ...

Problemi correlati