Edit:
Per divertimento, ho messo insieme un paio di regole che generalizzano l'accesso profondità arbitraria alle strutture della forma name([attr_1([attr_1_1,...attr_1_n([...])]), ..., attr_N([...]))
; Ad esempio, ai dati archiviati come fatti che hanno la stessa forma generale di my_computer/1
. Puoi usarlo, se vuoi.In ogni caso, si tratta di un bel po 'di dimostrazione della potente ricetta di Prolog dei predicati di ordine superiore + valutazione esplicita + homoiconicity:
attribute(Thing, Path) :-
call(Thing, Attributes),
path_through_attributes(Path, Attributes).
path_through_attributes(Path, Attributes) :-
(Path = (Func -> NextPath), atom(Func)
->
Attr =.. [Func, NextAttributes],
member(Attr, Attributes),
path_through_attributes(NextPath, NextAttributes)
;
compound(Path),
member(Path, Attributes)
).
Supponendo che abbiamo un fatto come my_computer/1
(proprio come appare nella prima parte della tua domanda), il predicato attribute/2
può essere utilizzato per accedere a qualsiasi dei suoi attributi, annidati a qualsiasi profondità, in questo modo:
?- attribute(my_computer, case(X)).
X = [motherboard([board(plastic), ports(metal), slots(plastic), capacitors(plastic)]), power_supply_unit([casing(metal), cables(plastic), connectors(plastic), capacitors(plastic), fan(plastic), transformer(...)]), central_processing_unit([board(plastic), fan(plastic), heatsink(metal)]), random_access_memory([board(plastic)]), graphics_processing_unit([board(plastic), ports(metal), capacitors(...)|...])]
?- attribute(my_computer, case -> power_supply_unit(X)).
X = [casing(metal), cables(plastic), connectors(plastic), capacitors(plastic), fan(plastic), transformer(metal)]
?- attribute(my_computer, case -> power_supply_unit -> transformer(X)).
X = metal
ho scelto l'operatore ->/2
per la funzione di accesso percorso semplicemente perché ha una comoda associatività (ie , a destra: (a -> (b -> c))
) ed è un po 'suggestivo e di "raggiungere una serie di termini annidati". Ma probabilmente non è una grande scelta. Se avessi intenzione di usarlo frequentemente, sarei venuto con un buon operatore per lo scopo e lo dichiarerei con op/3
.
Dal momento che tutti i termini in my_computer/1
sono in una lista, si potrebbe fare un predicato di accesso generale usando membro:
computer_attribute(Attr) :-
my_computer(Attributes),
member(Attr, Attributes).
Esso può essere utilizzato in questo modo:
?- computer_attribute(monitor(X)).
X = [lcd_screen(plastic), inverter(plastic), frame(plastic)]
Di Ovviamente, poiché monitor
è nidificato in case
, è necessario disporre di un approccio più specifico per accedere al primo.
A seconda dell'elaborazione dei dati, questo potrebbe essere un buon uso di pairs, association lists o records. (C'è anche la nuova estensione Prolog SWI che fornisce il composto dict
, ma io non lo consiglio, ho trovato che sono più problemi che valgono, ma potrebbe essere solo un difetto al mio fianco.)
Il rientro del secondo blocco di codice fa sembrare che esista una relazione gerarchica tra il fattore my_computer/1
e gli altri, ma questa è un'illusione. Una corretta indentazione chiarisce che ciascuno è semplicemente dichiarato come fatto autonomo:
my_computer([case,monitor,keyboard,mouse]).
case([motherboard,power_supply_unit,central_processing_unit,random_access_memory,graphics_processing_unit]).
motherboard([board,ports,slots,capacitors]).
power_supply_unit([casing,cables,connectors,capacitors,fan,transformer]).
central_processing_unit([board,fan,heatsink]).
random_access_memory([board]).
graphics_processing_unit([board,ports,capacitors,fan,heatsink]).
monitor([lcd_screen,inverter,frame]).
keyboard(keys,frame,cable).
mouse([keys,wheel,casing,cable]).
Di conseguenza, questa rappresentazione funziona solo se si dispone di un solo computer con le parti interessate in un dato spazio dei nomi. In caso contrario, se si dispone di un secondo computer, non sarà possibile stabilire quale chiamata a mouse(X)
deve essere associata a quale computer. Tuttavia, è possibile assegnare a ciascun computer un nome e quindi definire i diversi attributi come relazioni tra il nome del computer e un elenco di termini. Allora la vostra rappresentazione vorrebbe così:
computer(mine).
case(mine, [motherboard,power_supply_unit,central_processing_unit,random_access_memory,graphics_processing_unit]).
....
Questo codice può essere interrogato in questo modo:
?- computer(Name), motherboard(Name, Specs).
Name = mine,
Specs = [board, ports, slots, capacitors].
(Una volta che si dispone di una solida conoscenza di Prolog, si potrebbe desiderare di indagare Logtalk, che è un OOP estensione per Prolog. Non l'ho mai usato, ma sembra divertente.)
Non deve esserci uno spazio davanti alla parentesi rotonda di apertura e la parola precedente (più volte). Quindi scrivi 'mouse (' ecc. – false
@false ora per darmi questo X = [caso ([scheda madre ([scheda (plastica), porte (metallo), slot (plastica), condensatori (plastica)]), power_supply_unit ([ involucro (di metallo), cavi (di plastica), connettori (di plastica), condensatori (...) | ...]), unità_produttiva_ centrale ([scheda (plastica), ventola (di plastica), dissipatore di calore (...)]), random_access_memory ([board (plastic)]), graphics_processing_unit ([board (...) | ...])]), monitor ([lcd_screen (plastica), inverter (plastica), cornice (plastica)]), tastiera ([tasti (plastica), cornice (plastica), cavo (plastica)]), mouse ([tasti (plastica), ruota (plastica), involucro (plastica), cavo (...)])]. – Crownless
Perfetto! esattamente quello che stai descrivendo.Se vuoi accedere ai dettagli, ti consiglio di prendere prima un libro Prolog, come Art of Prolog e di imparare prima la lingua .. – false