mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
175 lines
4.6 KiB
Mathematica
175 lines
4.6 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-1995, 1997-1999, 2005-2006, 2011-2012 The University of Melbourne.
|
|
% Copyright (C) 2014-2016, 2018, 2025-2026 The Mercury team.
|
|
% This file is distributed under the terms specified in COPYING.LIB.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: stack.m.
|
|
% Main author: fjh.
|
|
% Stability: high.
|
|
%
|
|
% This file contains a stack abstract data type.
|
|
% The concrete representation of each stack is a list.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module stack.
|
|
:- interface.
|
|
:- import_module list.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type stack(T).
|
|
|
|
% init = Stack:
|
|
% init(Stack):
|
|
%
|
|
% True if-and-only-if Stack is an empty stack.
|
|
%
|
|
:- func init = stack(T).
|
|
:- pred init(stack(T)::out) is det.
|
|
|
|
% is_empty(Stack):
|
|
%
|
|
% True if-and-only-if Stack is an empty stack.
|
|
%
|
|
:- pred is_empty(stack(T)::in) is semidet.
|
|
|
|
% is_full(Stack):
|
|
%
|
|
% This is intended to be true if-and-only-if Stack is a stack
|
|
% whose capacity is exhausted. This implementation allows
|
|
% arbitrary-sized stacks, so is_full always fails.
|
|
%
|
|
:- pred is_full(stack(T)::in) is semidet.
|
|
|
|
% push(Stack0, Elem) = Stack:
|
|
% push(Elem, Stack0, Stack):
|
|
%
|
|
% True if-and-only-if Stack is the stack which results from pushing Elem
|
|
% onto the top of Stack0.
|
|
%
|
|
:- func push(stack(T), T) = stack(T).
|
|
:- pred push(T::in, stack(T)::in, stack(T)::out) is det.
|
|
|
|
% push_list(Stack0, Elems) = Stack:
|
|
% push_list(Elems, Stack0, Stack):
|
|
%
|
|
% True if-and-only-if Stack is the stack which results from
|
|
% pushing the elements of the list Elems onto the top of Stack0.
|
|
%
|
|
:- func push_list(stack(T), list(T)) = stack(T).
|
|
:- pred push_list(list(T)::in, stack(T)::in, stack(T)::out) is det.
|
|
|
|
% top(Stack, Elem):
|
|
%
|
|
% True if-and-only-if Stack is a non-empty stack whose top element is Elem.
|
|
%
|
|
:- pred top(stack(T)::in, T::out) is semidet.
|
|
|
|
% det_top is like top except that it will call error/1 rather than
|
|
% failing if given an empty stack.
|
|
%
|
|
:- func det_top(stack(T)) = T.
|
|
:- pred det_top(stack(T)::in, T::out) is det.
|
|
|
|
% pop(Elem, Stack0, Stack):
|
|
%
|
|
% True if-and-only-if Stack0 is a non-empty stack whose top element is
|
|
% Elem, and Stack is the stack which results from popping Elem off Stack0.
|
|
%
|
|
:- pred pop(T::out, stack(T)::in, stack(T)::out) is semidet.
|
|
|
|
% det_pop is like pop except that it will call error/1 rather than
|
|
% failing if given an empty stack.
|
|
%
|
|
:- pred det_pop(T::out, stack(T)::in, stack(T)::out) is det.
|
|
|
|
% depth(Stack) = Depth:
|
|
% depth(Stack, Depth):
|
|
%
|
|
% True if-and-only-if Stack is a stack containing Depth elements.
|
|
%
|
|
:- func depth(stack(T)) = int.
|
|
:- pred depth(stack(T)::in, int::out) is det.
|
|
|
|
:- func to_list(stack(T)) = list(T).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module require.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type stack(T)
|
|
---> stack(list(T)).
|
|
|
|
init = Stack :-
|
|
stack.init(Stack).
|
|
|
|
init(stack([])).
|
|
|
|
is_empty(stack([])).
|
|
|
|
is_full(_) :-
|
|
semidet_fail.
|
|
|
|
push(!.Stack, X) = !:Stack :-
|
|
stack.push(X, !Stack).
|
|
|
|
push(Elem, !Stack) :-
|
|
!.Stack = stack(Elems),
|
|
!:Stack = stack([Elem | Elems]).
|
|
|
|
push_list(!.Stack, Xs) = !:Stack :-
|
|
stack.push_list(Xs, !Stack).
|
|
|
|
push_list([], !Stack).
|
|
push_list([Elem | Elems], !Stack) :-
|
|
stack.push(Elem, !Stack),
|
|
stack.push_list(Elems, !Stack).
|
|
|
|
top(stack([Elem | _]), Elem).
|
|
|
|
det_top(Stack) = X :-
|
|
stack.det_top(Stack, X).
|
|
|
|
det_top(Stack, Elem) :-
|
|
(
|
|
Stack = stack([Elem | _])
|
|
;
|
|
Stack = stack([]),
|
|
unexpected($pred, "top of empty stack")
|
|
).
|
|
|
|
pop(Elem, !Stack) :-
|
|
!.Stack = stack([Elem | Elems]),
|
|
!:Stack = stack(Elems).
|
|
|
|
det_pop( Elem, !Stack) :-
|
|
(
|
|
!.Stack = stack([Elem | Elems]),
|
|
!:Stack = stack(Elems)
|
|
;
|
|
!.Stack = stack([]),
|
|
unexpected($pred, "pop from empty stack")
|
|
).
|
|
|
|
depth(Stack) = Depth :-
|
|
stack.depth(Stack, Depth).
|
|
|
|
depth(Stack, Depth) :-
|
|
Stack = stack(Elems),
|
|
list.length(Elems, Depth).
|
|
|
|
to_list(stack(Elems)) = Elems.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module stack.
|
|
%---------------------------------------------------------------------------%
|