既然你提到了 ADT,我将使用 Logtalk(你可以在大多数 Prolog 系统上运行)首先定义一个堆栈协议/接口:
:- protocol(stack_protocol).
:- public(new/1).
:- mode(new(--stack), one).
:- info(new/1, [
comment is 'Creates a new empty stack.',
argnames is ['Stack']
]).
:- public(empty/1).
:- mode(empty(@stack), one).
:- info(empty/1, [
comment is 'True if the stack is empty.',
argnames is ['Stack']
]).
:- public(top/2).
:- mode(top(?stack, ?element), zero_or_one).
:- info(top/2, [
comment is 'True if Top is the top element of the stack.',
argnames is ['Stack', 'Top']
]).
:- public(push/3).
:- mode(push(?stack, ?element, ?stack), zero_or_one).
:- info(push/3, [
comment is 'Adds an element to the stack.',
argnames is ['Stack0', 'Element', 'Stack']
]).
:- public(pop/3).
:- mode(pop(?stack, ?element, ?stack), zero_or_one).
:- info(pop/3, [
comment is 'Removes an element from the stack.',
argnames is ['Stack0', 'Element', 'Stack']
]).
:- end_protocol.
我们现在可以定义堆栈 ADT 的实现。显而易见的选择就是使用列表:
:- object(stack,
implements(stack_protocol)).
new([]).
empty(Stack) :-
Stack == [].
top([Top| _], Top).
push(Stack, Element, [Element| Stack]).
pop([Element| Stack], Element, Stack).
:- end_object.
假设在stack.lgt 源文件中定义了协议和对象,示例调用将是:
| ?- {stack}.
...
% (0 warnings)
(4 ms) yes
| ?- stack::(
new(S0),
push(S0, 1, S1),
push(S1, 2, S2),
push(S2, 3, S3),
top(S3, T),
pop(S3, E, S)
).
E = 3
S = [2,1]
S0 = []
S1 = [1]
S2 = [2,1]
S3 = [3,2,1]
T = 3
yes
是否值得定义协议?当需要几种不同的实现(例如字典或随机数生成器)时,协议特别有用。但是,在这种情况下,列表是实现堆栈的自然候选者,以至于定义协议的用处主要在于它的教育价值。在大多数情况下,当需要堆栈时,程序员只需直接使用列表即可。