[mercury-users] Re: can one_solution/2 and unsorted_solutions/2 be det?

Fergus Henderson fjh at cs.mu.oz.au
Tue Oct 28 23:57:19 AEDT 1997


Bart Demoen, you wrote:
> 
> (my code is Prolog rather than Mercury, because it doesn't matter)
> 
> Don and I seem in favour of a predicate like once/1 that could have
> been implemented in Prolog as
> 
> 	once(Goal) :- Goal, !.

Why are you in favour of such a predicate?
Please show us a program in which it would be useful.

> but doesn't need to be. I would be perfectly happy if its semantics
> were rather like in
> 
> 	once(Goal) :-
> 		findall(Goal,Goal,ListOfGoal),
> 		random(N),
> 		nth_element(N,ListOfGoal,Goal).
> 
> and at each invocation - even with the same goal - returns a different
> solution. I would be happy with this semantics but not with its
> implementation.

What is the declarative semantics of `random(N)'?

> Now there is no garantee that for
> 
> 	a :- once(member(X,[1,2])), once(member(Y,[1,2])), X = Y.
> 
> 	?- a.
> 
> succeeds. It doesn't scare me a bit: I can already write it purely;
> once/1 is just that kind of a predicate.

No, you can't write it purely.  The semantics you give above for
once/1 are not pure, because random/1 is not pure.
(Nor is findall, for that matter.)

(Actually you _can_ make random/1 and findall/1 pure in Mercury,
but only by giving them committed choice determinisms,
and if you do that, then once/1 would have determinism `cc_multi'
not `det', which would defeat the purpose -- if you only use
once/1 in single-solution contexts, then Mercury will insert
pruning automatically, so there is no need to write once/1 explicitly.)

> Another aspect of the once/1 I like, cannot be simulated in Mercury:
> 
> 	a(X) :- once(member(X,[1,2])) ; once(member(X,[1,2])).
> 
> also with the random definition of once/1, the query ?- a(X).
> returns the same solution twice (modulo elimination of duplicate
> solutions :-) because random/1 returns the same random number in
> alternative branches.

Why do you like this aspect of once/1?

The once/1 procedure that you have defined cannot be reasoned about
using the declarative semantics.  You can only reason about it using
the operational semantics.  The operational semantics of Prolog is
complicated -- backtracking can be difficult to reason about.
If you want to give up the declarative semantics, you had better
have a good reason.  But I don't see _why_ you would want to
write examples like the a/1 above.

> I picked up once (sic) more the pruneslides.dvi that Lee recommended.
> There is a striking sentence on page 18 with different uses of once/1:
> 
> 	compile(I,O) - you want any solution (this may affect
> 	  completeness if used other than at the top level)
> 
> 
> One person's top level is another person's goal ...
>
> In real life, I very often want any solution (of a restricted set
> though) and [...] it is mostly not at my top level.

Perhaps your complaint is based on lack of knowledge about how to use
Mercury.  Mercury does allow you to use `cc_multi' predicates at places
other than the top level.  For example, suppose you have a procedure
`compute_answer' that computes an answer by invoking the
above-mentioned compile/2 predicate.  The most obvious way of writing
this in Mercury is as follows:

	:- pred compile(program::in, objectcode::out) is cc_multi.

	:- pred compute_answer(program::in, answer::out) is det.
	compute_answer(Program, Answer) :-
		compile(Program, ObjectCode),
		run(ObjectCode, Answer).

This doesn't quite work, because compile/2 is `cc_multi', whereas
compute_answer/2 was declared `det'.  But the solution is quite
straight-forward:

	:- pred compute_answer(program::in, answer::out) is det.
	compute_answer(Program, Answer) :-
		Answer = promise_one_solution(compute_answer_cc_multi(Program)).

	:- pred compute_answer_cc_multi(program::in, answer::out) is cc_multi.
	compute_answer_cc_multi(Program, Answer) :-
		compile(Program, ObjectCode),
		run(ObjectCode, Answer).

(Although this solution is straight-forward, it is not quite ideal;
as Peter Schachte mentioned, the ideal way of solving this would be
by adding some sort of declaration, e.g.

	:- pragma promise_one_solution(compute_answer/2).

rather than by modifying the code for compute_answer/2.
Still, that is basically a minor matter of syntax.)

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the users mailing list