[mercury-users] Getting 'any' insts to ground

Bas de Bakker basde.bakker at pica.nl
Tue Nov 11 18:17:20 AEDT 1997

Fergus writes:

> That doesn't quite make sense, because the type `int' has
> no representation for the inst `any'.  Perhaps you meant

> 	:- pred fill_list(list(var(int))).

Right, that's what I used.  Sorry about the confusion.

> What's your aim -- do you (a) want your algorithm to be able to handle
> the case where the variable turns out not to be ground, or (b) do you
> expect that the variable will always be ground, but want to ensure that
> if you make a mistake, then the error will be detected at runtime?

My aim is (b), the program can abort if the variable is not ground.

> Both of these aims can be achieved using predicates that have
> a logical interface with a proper declarative semantics.

Thanks for all the help, it almost solves my problem.  As I indicated
in the mode declaraion, the fill_list predicate is nondeterministic
and will generate multiple solutions, which I all need.

The solution seems to be to have a get_val/2 predicate with a mode
that is actually declared as multi (but still operationally aborts
when called with a non-ground argument), but I don't know how to
implement this as it seems to require creating a 'multi' procedure in

For definiteness (and for interested readers), I've included my trial
program below, which is an adaptation of an N-queens program in "The
Art of Prolog".  After the call to place_queens in queens, I know that
Qs is ground.  It works, although it has no right to do so.

BUG REPORT: If I change the declaration of get_value to cc_multi, I
get an internal compiler error.

> 	:- pred is_ground(var(T), maybe(T)).
> 	:- mode is_ground(in(any), out) is cc_multi.

This raises quite a different problem.  Let's say we have something

	is_ground(X, Y).

The compiler could (at least in the commutative semantics) call
is_ground _before_ dosomething, making Y equal to 'no' (which is a
correct interpretation of the declarative semantics of the program).
This is why in my previous message I tried to suggest an is_ground/1
with mode any->ground.

> Fortunately there are a number of different solutions to this problem
> of calling cc_multi predicates from a det context, as has been
> discussed in detail in recent mail to mercury-users.  I haven't
> investigated how well they work in these sort of cases, however.

As I've only been on this list for a few days, I have not seen this
message and it does not yet seem to be in the archive.

% This is a kind of -*- prolog -*-

:- module queen.

:- interface.

:- pred main(io__state, io__state).
:- mode main(di, uo) is cc_multi.

:- implementation.

:- import_module io.
:- import_module std_util.
:- import_module int.
:- import_module list.
:- import_module var.
:- import_module unsafe.
:- import_module string.
:- import_module require.

:- type list == list(int).
:- type vlist == list(var(int)).

main -->
	{ get_numeric_arg1(Args, N) },

:- pred get_numeric_arg1(list(string), int).
:- mode get_numeric_arg1(in, out) is det.

get_numeric_arg1(Args, N) :-
	Args = [Arg1|_],
	string__to_int(Arg1, N)
	error("Usage: queen N").

:- pred writeln(T, io__state, io__state).
:- mode writeln(in, di, uo) is det.

writeln(X) -->

:- pred queen(int, io__state, io__state).
:- mode queen(in, di, uo) is cc_multi.

queen(N) -->
	unsorted_aggregate(queens(N), writeln).

% create_list(N, Xs) is true if Xs is a list of N var(int)
% terms.

:- pred create_list(int, vlist).
:- mode create_list(in, out(list_skel(any))) is det.

create_list(N, Xs) :-
        (N = 0 ->
             Xs = []
        N1 = N - 1,
        create_list(N1, Ys),
        Xs = [V|Ys]).

% cheated_is_ground is only used as a helper in get_value/2 below.
% It is cheated, because I've declared it as multi, while it isn't.
% The declaration of get_value as multi is correct, however.

:- pred cheated_is_ground(var(T), maybe(T)).
:- mode cheated_is_ground(in(any), out) is multi.

% Copied implementation from var__is_ground
% This seems to work, which is pure luck as there is no documented
% way to implement a multi or nondet mode of a predicate in C.

:- pragma c_code(cheated_is_ground(Var::in(any), Result::out),
	ML_var_is_ground(TypeInfo_for_T, Var, &Result);

:- pred get_value(var(T), T).
:- mode get_value(in(any), out) is multi.

get_value(Var, Value) :-
	cheated_is_ground(Var, MaybeValue),
	( MaybeValue = yes(V) ->
	      Value = V
	error("var__get_val: variable not ground"), fail

% convert/2 converts a list of var(int) to a list of int.
% Although declared as multi, it can actually succeed only once.

:- pred convert(vlist, list).
:- mode convert(in(list_skel(any)), out) is multi.

convert([], []).

convert([N1|Xs], [N2|Ys]) :-
	get_value(N1, N2),
	convert(Xs, Ys).

% queens(N, Queens) is true if Queens is a solution to the N-queens
% problem.
% The lines that create Ups and Downs are not necessary in Prolog.

:- pred queens(int, list).
:- mode queens(in, out) is nondet.

queens(N, Queens) :-
	create_list(N, Qs),
	create_list(N + 1, Ups),
	create_list(2 * N, Downs),
	place_queens(N, Qs, Ups, Downs),
	convert(Qs, Queens).

% Pass around lists of 'any'
:- mode vmode :: in(list_skel(any)).

:- pred place_queens(int, vlist, vlist, vlist).
:- mode place_queens(in, vmode, vmode, vmode) is nondet.

place_queens(I, Qs, Ups, [_|Downs]) :-
	(I = 0 ->
	place_queens(I - 1, Qs, [U|Ups], Downs),
	place_queen(I, Qs, Ups, Downs)

:- pred place_queen(int, vlist, vlist, vlist).
:- mode place_queen(in, vmode, vmode, vmode) is nondet.

place_queen(Q, [var(Q)|_], [var(Q)|_], [var(Q)|_]).

place_queen(Q, [_|Qs], [_|Ups], [_|Downs]) :-
	place_queen(Q, Qs, Ups, Downs).

% Avoid link errors from libtrailed_update.a
% What is the idea behind this anyway?
:- pragma c_code("
void report_goal_floundered(void);
void report_goal_floundered(void) { exit(1); }

More information about the users mailing list