[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
C.
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
like
var__init(X),
dosomething(X),
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.
Regards,
Bas.
------------------------------------------------------------------------
% 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 -->
command_line_arguments(Args),
{ get_numeric_arg1(Args, N) },
queen(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) -->
io__write(X),
io__nl.
:- 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),
var__init(V),
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),
may_call_mercury,
"
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 ->
true
;
var__init(U),
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