[mercury-users] Modes for partly uninstantiated list

Ralph Becket rafe at csse.unimelb.edu.au
Mon Feb 5 08:53:16 AEDT 2007


Hi,

"vanilla" Mercury doesn't support Prolog-style variables (i.e.,
variables with aliasing where you can constrain X = Y before X or Y have
been bound to anything), which is what you're trying to do here.  The
reasons why we don't support aliasing include (a) it causes all sorts of
logical problems in negations and (b) it leads to major, major
performance problems.

Mercury does, however, support solver types which can do what you want.
These are still somewhat experimental and details are likely to change.

I recommend you try expressing your problem using a ground data
structure instead, in order to get a feel for common Mercury style.
For example:

	% The board is a tuple of squares representing a 3x3 grid.
	%
:- type board == {sq, sq, sq, sq, sq, sq, sq, sq, sq}.

	% A square contains o, x, or e (empty).
	%
:- type sq ---> o ; x ; e.

	% A useful subtype inst for non-empty sq values.
	%
:- inst player ---> o ; x.

:- func new_board = board.

new_board = {e, e, e, e, e, e, e, e, e}.

	% Detect a win for either player.
	%
:- pred win(board::in) is semidet.

win(Board) :- win(o, Board).
win(Board) :- win(x, Board).

	% Detect a win for x or o (note the "subtype" inst in the mode).
	%
:- pred win(sq::in(player), board::in) is semidet.

win(P, {P, P, P, _, _, _, _, _, _}).
win(P, {_, _, _, P, P, P, _, _, _}).
win(P, {_, _, _, _, _, _, P, P, P}).
win(P, {P, _, _, P, _, _, P, _, _}).
etc.

	% Update the board given a square number and player.
	%
:- pred update_board(int::in, sq::in(player), board::in, board::out)
	is semidet.

update_board(1, P, {e, B, C, D, E, F, G, H, I}, {P, B, C, D, E, F, G, H, I}).
update_board(2, P, {A, e, C, D, E, F, G, H, I}, {A, P, C, D, E, F, G, H, I}).
update_board(3, P, {A, B, e, D, E, F, G, H, I}, {A, B, P, D, E, F, G, H, I}).
etc.

Once you've tried that, if you still want to find out how to use solver
types, write back to the mailing list and we'll respond in more detail
when we have time.

Below I've made some comments about your code explaining things that
don't work the same way in Mercury.

C. Heppner, Saturday,  3 February 2007:
> Hi,
> 
> I've been doing a little thing about a game called tick-tack-toe in
> prolog. Now I'd like to try the same in mercury.
> 
> The predicate I am having trouble with is:
> 
> win([A,B,C,_,_,_,_,_,_]) :- atom(A), atom(B), atom(C), A=B, B=C.
> win([_,_,_,A,B,C,_,_,_]) :- atom(A), atom(B), atom(C), A=B, B=C.
> win([_,_,_,_,_,_,A,B,C]) :- atom(A), atom(B), atom(C), A=B, B=C.
> 
> win([A,_,_,B,_,_,C,_,_]) :- atom(A), atom(B), atom(C), A=B, B=C.
> win([_,A,_,_,B,_,_,C,_]) :- atom(A), atom(B), atom(C), A=B, B=C.
> win([_,_,A,_,_,B,_,_,C]) :- atom(A), atom(B), atom(C), A=B, B=C.
> 
> win([A,_,_,_,B,_,_,_,C]) :- atom(A), atom(B), atom(C), A=B, B=C.
> win([_,_,A,_,B,_,C,_,_]) :- atom(A), atom(B), atom(C), A=B, B=C.

You're using atom/1 which is non-logical and isn't supported in Mercury.
Except for solver types,
- Mercury insists on being told the instantiation state of every
  predicate argument in a mode declaration.
- Mercury doesn't support partial instantiation or aliasing.

> I've tried different things in mercury but didn't succeed. My
> test-code looks like the following:
> 
> 
> :- pred win(list(character)).
> :- mode win(list_skel >> list_skel) is semidet.
> 
> win([A,B,C,_,_,_,_,_,_]) :- A=B, B=C.
> 
> main(!IO) :-
> 	L = [x,x,x,_,_,_,_,_,_],
> 	(if win(L)
> 		then write_string("win", !IO)
> 		else write_string("not(win)", !IO)),
> 	nl(!IO).
> 
> The errors I get:
> 
> ticktack.m:043: In clause for `main(di, uo)':
> ticktack.m:043:   in argument 1 of call to predicate `ticktack.win/1':
> ticktack.m:043:   sorry, implied modes not implemented.
> ticktack.m:043:   Variable `L' has instantiatedness
> ticktack.m:043:   `unique(list.'[|]'(unique(x),
> unique(list.'[|]'(unique(x),
> ticktack.m:043:   unique(list.'[|]'(unique(x), unique(list.'[|]'(free,
> ticktack.m:043:   unique(list.'[|]'(free, unique(list.'[|]'(free,
> ticktack.m:043:   unique(list.'[|]'(free, unique(list.'[|]'(free,
> ticktack.m:043:   unique(list.'[|]'(free,
> unique((list.[]))))))))))))))))))))',
> ticktack.m:043:   expected instantiatedness was `bound((list.[]) ;
> ticktack.m:043:   list.'[|]'(free, bound((list.[]) ;
> list.'[|]'(free, ...))))'.
> ticktack.m:018: In clause for `win(((list.list_skel) >>
> (list.list_skel)))':
> ticktack.m:018:   mode error in unification of `A' and `B'.
> ticktack.m:018:   Variable `A' has instantiatedness `free',
> ticktack.m:018:   variable `B' has instantiatedness `free'.
> 
> 
> I would intuitively try it with something like that (which doesn't
> work, too):
> 
> win([A::in,A::in,A::in,_,_,_,_,_,_]).

You'd need to write

:- mode win(in) is semidet.

instead.  But then you'd have to ensure that list arguments to win/1
are completely ground (i.e., contains no unbound variables).  Have a
look at my sample code above for one way to do it.

Cheers,
-- Ralph

--------------------------------------------------------------------------
mercury-users mailing list
Post messages to:       mercury-users at csse.unimelb.edu.au
Administrative Queries: owner-mercury-users at csse.unimelb.edu.au
Subscriptions:          mercury-users-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the users mailing list