假设我有对象
a1,a2,...,a{n}
,我想对这些对象有效地引入一个顺序,例如:
gt(a1,a2).
gt(a2,a3).
...
gt(a{n-1},a{n}).
现在
{n}
会是一个很大的数字,比如 200。而不是写成 199 个事实。在 Prolog 中是否有“更好”的方法来做到这一点?
我正在考虑定义一个列表,然后将
gt
应用于该列表的 zip
并对其进行移动。
如果这完全违背了 Prolog 的使用方式,并且必须竭尽全力才能找到这样的解决方案,那么我完全接受一个简短的解释来说明为什么这是答案。
如何将它们按从小到大的顺序放入列表中,以及描述它们在列表中的关系的语法:
cards([ace, two, three, four, five, six, seven,
eight, nine, ten, jack, queen, king]).
% see https://www.metalevel.at/prolog/dcg "any sequence at all"
... --> [] | [_], ... .
gt_([Small, Big]) --> ..., [Small], ..., [Big].
gt(Big, Small) :-
cards(Cards),
phrase(gt_([Small, Big]), Cards, _).
由于这会消耗列表一次,因此它在算法上稍微干净一些,但可能比以下内容不太清晰并且开销更大:
cards([ace, two, three, four, five, six, seven,
eight, nine, ten, jack, queen, king]).
gt(Smaller, Bigger) :-
cards(Cards),
nth1(Sindex, Cards, Smaller),
nth1(Bindex, Cards, Bigger),
Bindex > Sindex.
两者都留下选择点,并且都可以用来生成诸如“X 皇后比什么大?”之类的查询的答案。
以下版本将列表中的元素与索引列表配对,不会留下选择点,但无法生成答案:
cards([ace, two, three, four, five, six, seven,
eight, nine, ten, jack, queen, king]).
gt(Smaller, Bigger) :-
cards(Cards),
length(Cards, Len),
numlist(1, Len, Counts),
pairs_keys_values(Pairs, Cards, Counts),
memberchk(Smaller-Sindex, Pairs),
memberchk(Bigger-Bindex, Pairs),
Bindex > Sindex.
最后两个对数字进行简单的比较,因此对于像 Queen > ace 这样的东西,它避免了必须跟踪整个传递关系 queen > jack > 10 > 9 > ... 2 > ace,但它确实必须扫描多次列出。
您可以将它们放入 SWI Prolog 字典中以获得更快的查找速度,但语法不标准。或者循环遍历它们,将信息放入 Prolog 数据库中,这似乎不推荐,或者更容易编写一些代码一次为您写出 199 个事实,然后将其复制粘贴到您的代码中。 (也许是:
assertz
然后查询两次并比较值。
% card(name, value)
card(ace, 1).
card(two, 2).
...
card(king, 13).
这是完全相关的 - 导致 swi-prolog:
% Human-convenient order
card_order(ace).
card_order(ten).
card_order(king).
% Fill in the rest yourself
populate_order_nums :-
nb_setval(cards, 1),
forall(
card_order(Card),
( nb_getval(cards, I),
% Create facts of e.g. card(ten, 2)
assertz(card(Card, I)),
I1 is I + 1,
nb_setval(cards, I1)
)
).
% Runs this when the program is loaded
:- populate_order_nums.
% Fast, indexed lookup
card_lower_higher(CL, CH) :-
card(CL, Low),
card(CH, High),
Low @< High.