mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-26 14:54:17 +00:00
Estimated hours taken: 70 (plus whatever pets spent when he wrote the original version of this) This change adds a new extras directory, "references". This directory contains two impure reference type modules and a module that allows scoped non-backtrackable update, along with examples of using them and tests. These modules are intended to be useful when HAL is retargetted to Mercury, for implementing global variables (backtracking and non-backtracking), and may also be useful for the debugger. In order to implement these features, a new memory zone "global heap" was added to the runtime system, for a heap which is not reclaimed on failure, along with a pair of functions for copying terms to this heap. runtime/mercury_deep_copy.c: runtime/mercury_deep_copy.h: Added two functions, MR_make_permanent() and MR_make_partially_permanent(), which essentially do a deep copy of a term to the global heap. (In conservative GC grades, these functions actually do nothing). runtime/mercury_engine.c: runtime/mercury_engine.h: Added fields global_heap_zone and e_global_hp (for the global heap and its heap pointer) to the MR_mercury_engine_struct, along with appropriate initialisation, etc. Defined MR_heap_zone, MR_solutions_heap_zone, and MR_global_heap_zone for convenient access to the corresponding field of the relevant Mercury engine. runtime/mercury_memory.c: Added code for handling the size and zone size of the global heap. runtime/mercury_regorder.h: runtime/mercury_regs.h: Defined MR_global_hp (the global heap pointer for general use), along with corresponding other changes. runtime/mercury_wrapper.c: runtime/mercury_wrapper.h: Added declarations and initialisation of the size and zone_size of the global_heap. Added an entry for MR_GLOBAL_HP_RN to print_register_usage_counts() (plus missing entries for MR_SOL_HP_RN, MR_MIN_HP_REC and MR_MIN_SOL_HP_REC). New files: extras/references/Mmakefile: Mmakefile for building and testing these modules. extras/references/README: Description of contents of this directory. extras/references/global.m: A wrapper module for building a library containing the nb_reference, reference and scoped_update modules. extras/references/nb_reference.m: Implements references which are not backtracked on failure. extras/references/reference.m: Implements references which *are* backtracked on failure. extras/references/scoped_update.m: Allows nested scoping of non-backtracking references. extras/references/samples/Mmakefile: extras/references/samples/max_of.m: extras/references/samples/max_test.exp: extras/references/samples/max_test.m: An example of using a non-backtracking reference (to find the maximum of the solutions generated by a predicate), with tests. extras/references/tests/Mmakefile: extras/references/tests/ref_test.exp: extras/references/tests/ref_test.m: Some tests of references (backtracking and non-backtracking) and scoping.
97 lines
3.2 KiB
Mathematica
97 lines
3.2 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1998 University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File : max_of.m
|
|
% Authors : pets (Peter Schachte)
|
|
% Stability : low
|
|
% Purpose : demonstration of nb_reference type
|
|
%
|
|
% This module defines a predicate max_of/2 that is equivalent to
|
|
%
|
|
% max_of(Pred, Max) :-
|
|
% unsorted_solutions(Pred, List),
|
|
% List = [First|Rest],
|
|
% foldl((pred(X,Y,Z) is det :- max(X,Y,Z)), Rest, First, Max).
|
|
%
|
|
% but which is potentially more efficient, because it avoids building a
|
|
% list of solutions.
|
|
|
|
:- module max_of.
|
|
:- interface.
|
|
|
|
:- pred max_of(pred(int), int).
|
|
:- mode max_of(pred(out) is nondet, out) is semidet.
|
|
:- mode max_of(pred(out) is multi, out) is det.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module nb_reference.
|
|
:- import_module int, bool.
|
|
|
|
% This implementation uses two non-backtrackable references, one to keep
|
|
% track of whether or not we've had any solutions, and the other to store the
|
|
% max "so far." For each solution we find, if it's the first, we set the max
|
|
% so far to it, and we record that we've had some solutions. If not the
|
|
% first solution, then we update the max if the new solution is larger than
|
|
% the max so far. When we've found all the solutions, we make sure we've
|
|
% found at least one solution, and then return the max so far as the result.
|
|
%
|
|
% There is one difficulty implementing this predicate. When the Pred
|
|
% argument is a multi closure, we want max_of to be det. But when Pred is
|
|
% nondet, we must check to make sure than we have had any solutions; if not,
|
|
% max_of/2 must fail. Unfortunately, the Mercury compiler can't determine
|
|
% that when Pred is multi, the test will always succeed, so the determinacy
|
|
% checker complains that max_of/2 in that mode is actually semidet. We work
|
|
% around that with the min_solutions/1 predicate, which is implemented with
|
|
% C code. This allows us to have different code for different modes, which
|
|
% allows us to work around the problem. It would be much more convenient if
|
|
% Mercury allowed us to have different code for different modes of a
|
|
% predicate implemented in Mercury.
|
|
|
|
|
|
:- pragma promise_pure(max_of/2).
|
|
|
|
max_of(Pred, Max) :-
|
|
impure new_nb_reference(no, Someref),
|
|
impure new_nb_reference(0, Maxref),
|
|
(
|
|
Pred(Value),
|
|
semipure value(Someref, Some),
|
|
( Some = no ->
|
|
impure update(Someref, yes),
|
|
impure update(Maxref, Value)
|
|
;
|
|
semipure value(Maxref, Prev),
|
|
( Value > Prev ->
|
|
impure update(Maxref, Value)
|
|
;
|
|
true
|
|
)
|
|
),
|
|
fail
|
|
;
|
|
impure min_solutions(Pred, MinSolutions),
|
|
(
|
|
MinSolutions = 1
|
|
;
|
|
semipure value(Someref, yes)
|
|
),
|
|
semipure value(Maxref, Max)
|
|
).
|
|
|
|
|
|
:- impure pred min_solutions(pred(T), int).
|
|
:- mode min_solutions(pred(out) is nondet, out(bound(0))) is det.
|
|
:- mode min_solutions(pred(out) is multi, out(bound(1))) is det.
|
|
|
|
:- pragma c_code(
|
|
min_solutions(_Pred::(pred(out) is nondet), Res::out(bound(0))),
|
|
will_not_call_mercury, "Res = 0;").
|
|
:- pragma c_code(
|
|
min_solutions(_Pred::(pred(out) is multi), Res::out(bound(1))),
|
|
will_not_call_mercury, "Res = 1;").
|
|
|