my_computer([
case([
motherboard([board(plastic),ports(metal),slots(plastic),capacitors(plastic)]),
power_supply_unit([casing(metal),cables(plastic),connectors(plastic),capacitors(plastic),fan(plastic),transformer(metal)]),
central_processing_unit([board(plastic),fan(plastic),heatsink(metal)]),
random_access_memory([board(plastic)]),
graphics_processing_unit([board(plastic),ports(metal),capacitors(plastic),fan(plastic),heatsink(metal)])
]),
monitor([
lcd_screen(plastic),inverter(plastic),frame(plastic)
]),
keyboard([
key(plastic),frame(plastic),cable(plastic)
]),
mouse([
key(plastic),wheel(plastic),casing(plastic),cable(plastic)
])
]).
我应该怎么做才能运行monitor(X).
或motherboard(X)
等问题来提供一个或所有(子)材料层(如my_computer(X).
那样)?
以下代码对于提出此类问题会更有用吗?关于一层子材料的问题很容易以这种方式回答。
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]).
答案 0 :(得分:2)
对你的问题的简短回答是:
monitor(X) :-
my_computer([_, monitor(X), _, _]).
同样适用于keyboard
或mouse
等。motherboard
会更深层次:
motherboard(X) :-
my_computer([case([motherboard(X), _, _, _, _), _, _, _]).
这些谓词当然假设一个固定的结构。如果你想要它更通用一些,你可以对嵌入式仿函数(monitor
,motherboard
等)进行更精细的“搜索”。
根据您更广泛的应用目标,我不清楚这是数据的最佳表示。现在已经够好了,但是上下文可能想要把它带到另一个方向。
<小时/> 这是另一种方法,将数据视为暗示树关系的个别事实。基本上只是
has
关系。将“重要”事实分开为material(Item, Type)
:
item(my_computer, case).
item(my_computer, monitor).
item(my_computer, keyboard).
item(my_computer, mouse).
item(case, motherboard).
item(case, power_supply_unit).
item(case, central_processing_unit).
item(case, random_access_memory).
item(case, graphics_processing_unit).
item(motherboard, board).
item(motherboard, ports).
item(motherboard, slots).
item(motherboard, capacitors).
item(power_supply_unit, casing).
item(power_supply_unit, cable).
item(power_supply_unit, connectors).
item(power_supply_unit, capacitors).
item(power_supply_unit, fan).
item(power_supply_unit, transformer).
item(central_processing_unit, board).
item(central_processing_unit, fan).
item(central_processing_unit, heatsink).
item(random_access_memory, board).
item(graphics_processing_unit, board).
item(graphics_processing_unit, ports).
item(graphics_processing_unit, capacitors).
item(graphics_processing_unit, fan).
item(graphics_processing_unit, heatsink).
item(monitor, lcd_screen).
item(monitor, inverter).
item(monitor, frame).
item(keyboard, key).
item(keyboard, frame).
item(keyboard, cable).
item(mouse, key).
item(mouse, wheel).
item(mouse, casing).
item(mouse, cable).
material(board, plastic).
material(slots, plastic).
material(capacitors, plastic).
material(ports, metal).
material(casing, metal).
material(cable, plastic).
material(connectors, plastic).
material(fan, plastic).
material(heatsink, metal).
material(lcd_screen, plastic).
material(inverter, plastic).
material(frame, plastic).
material(key, plastic).
material(cable, plastic).
然后,您可以定义谓词以生成您希望的任何级别的树。这是一个以术语(不是列表)的形式来做的例子:
structure(Item, Structure) :-
( item(Item, _)
-> findall(T, (item(Item, R), structure(R, T)), Rs),
Structure =.. [Item |Rs]
; Structure = Item
).
那么:
:- structure(case, S).
S = case(motherboard(board,ports,slots,capacitors),
power_supply_unit(casing,cable,connectors,capacitors,fan,transformer),
central_processing_unit(board,fan,heatsink),
random_access_memory(board),
graphics_processing_unit(board,ports,capacitors,fan,heatsink)
)
这可以很容易地更改为以列表形式提供结果。例如,这是一个谓词,它采用上述事实并提供您最初在问题中提出的表单:
structure(Item, Tree) :-
( item(Item, _)
-> findall(T, (item(Item, R), structure(R, T)), Rs),
Tree =.. [Item, Rs]
; material(Item, Material),
Tree =.. [Item, Material]
).
item
成为where_used(Item, Parent)
谓词的一个简单结果:
where_used(Item, Parent) :-
item(Parent, Item).
同样,这完全取决于您希望如何使用和管理数据。
答案 1 :(得分:2)
修改强>
为了好玩,我拼凑了一对规则,这些规则概括了对name([attr_1([attr_1_1,...attr_1_n([...])]), ..., attr_N([...]))
形式结构的任意深度访问;即,存储为与my_computer/1
具有相同通用形式的事实的数据。如果你愿意,你可以使用它。无论如何,这是Prolog强有力的高阶谓词+明确评价+同质性的一个很好的小证明:
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)
).
假设我们有my_computer/1
这样的事实(正如问题的第一部分所示),谓词attribute/2
可用于访问任何属性,嵌套在任何深度,像这样:
?- 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
我选择->/2
运算符作为访问者路径只是因为它具有方便的关联性(即右:(a -> (b -> c))
),它有点暗示“进入一系列嵌套术语”。但它可能不是一个很好的选择。如果我经常使用它,我会为此目的找到一个好的运算符并用op/3
声明它。
由于my_computer/1
中的所有术语都在列表中,因此您可以使用成员创建一般访问谓词:
computer_attribute(Attr) :-
my_computer(Attributes),
member(Attr, Attributes).
可以像这样使用:
?- computer_attribute(monitor(X)).
X = [lcd_screen(plastic), inverter(plastic), frame(plastic)]
当然,由于monitor
嵌套在case
中,因此您需要采用更具体的方法来访问前者。
根据数据的详细程度,这可能是pairs,association lists或records的一个很好的用例。 (还有新的SWI Prolog扩展提供dict
化合物,但我不推荐它。我发现它们比它们值得更麻烦。但这可能只是我身边的一个缺点。 )
第二个代码块的缩进使得my_computer/1
事实与其他代码之间存在层次关系,但这是一种幻觉。适当的缩进表明每个都被简单地说成是一个独立的事实:
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]).
因此,只有在给定命名空间中只有一台计算机具有相关部分时,此表示才有效。否则,如果您有第二台计算机,您将无法分辨哪个mouse(X)
的呼叫与哪台计算机相关联。但是,您可以为每台计算机命名,然后将不同的属性定义为计算机名称和术语列表之间的关系。那你的代表就是这样:
computer(mine).
case(mine, [motherboard,power_supply_unit,central_processing_unit,random_access_memory,graphics_processing_unit]).
....
可以像这样查询此代码:
?- computer(Name), motherboard(Name, Specs).
Name = mine,
Specs = [board, ports, slots, capacitors].
(一旦你掌握了Prolog,你可能想要调查Logtalk,这是Prolog的OOP扩展。我从未使用它,但听起来很有趣。)
答案 2 :(得分:1)
您还可以使用明确的子句语法规则(DCG)定义物料清单(BOM)。例如:
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].
具有组件的零件,例如monitor
,表示为非终端。不是由其他部件制成的零件,例如keys
表示为终端(即方括号之间)。标准phrase/2
谓词可用于获取特定部分的物料清单。例如:
| ?- phrase(monitor, Parts).
Parts = [lcd_screen,inverter,frame]
yes
| ?- phrase(case, Parts).
Parts = [board,ports,slots,capacitors,casing,cables,connectors,capacitors,fan,transformer,board,fan,heatsink,board,board,ports,capacitors,fan,heatsink]
yes
如果您需要表示特定部分的详细信息,例如风扇有三种不同的模式,其中一种具有自己的RPM,您可以将部件名称(原子)解释为Prolog模块或Logtalk对象标识符。然后,模块或对象可以很好地保存有关零件的详细信息。