[mercury-users] Equivalent of Prolog setof with free variable

Jeff Thompson jeff at thefirst.org
Fri Jan 27 18:29:20 AEDT 2012


On 1/25/2012 7:53 AM, Julien Fischer wrote:
>
> Hi,
>
> On Tue, 24 Jan 2012, Jeff Thompson wrote:
>
>> Hello.  What is the preferred way in Mercury to implement the 
>> equivalent of setof with a free variable.  For example, Prolog:
>>
>> person(bob, accounting).
>> person(alice, accounting).
>> person(fred, sales).
>>
>> departmentMembers(Department, People) :-
>>  setof(Person, person(Person, Department), People).
>>
>> Calling departmentMembers returns multiple times with results for the 
>> free variable:
>> Department = accounting,
>> People = [alice, bob] ;
>>
>> Department = sales,
>> People = [fred].
>>
>> What is the preferred way to get this in Mercury?
>
> As Michael has mentioned, you will need to use the all-solutions
> predicates from the standard library's solutions module.
>
> A possible Mercury implementation of the above is:
>
>     :- module foo.
>     :- interface.
>     :- pred main(io::di, io::uo) is det.
>     :- implementation.
>
>     :- import_module list.
>     :- import_module set.
>     :- import_module solutions.
>     :- import_module string.
>
>     :- type person ---> alice ; bob ; fred.
>
>     :- type department ---> accounting ; sales.
>
>     :- pred departmentMembers({department, list(person)}::out) is multi.
>
>     departmentMembers({Department, People}) :-
>        person(_, Department),
>        solutions((pred(P::out) is multi :- person(P, Department)), 
> People).
>
>     :- pred person(person, department).
>     :- mode person(out, in) is multi.
>     :- mode person(out, out) is multi.
>
>     person(bob, accounting).
>     person(alice, accounting).
>     person(fred, sales).
>
> And since Mercury doesn't have an interactive top-level:
>
>     main(!IO) :-
>         solutions(departmentMembers, Solns),
>         io.write_list(Solns, "\n\n", output_soln, !IO),
>         io.nl(!IO).
>
>     :- pred output_soln({department, list(person)}::in, io::di, 
> io::uo) is det.
>
>     output_soln({Department, People}, !IO) :-
>         io.format("Department = %s,\nPeople = %s",
>         [s(string(Department)), s(string(People))], !IO).
>
> Julien.

I'm looking for a single-pass implementation, since departmentMembers 
above makes multiple passes through person. (While person is a simple 
lookup, imagine a more complicated predicate where multiple passes is 
expensive.)  I implemented a bagof predicate (see below) so that 
departmentMembers changes to:

departmentMembers({Department, People}):-
   bagof((pred(D - P ::out) is multi :- person(P, D)), Department, People).

Since I'm a newbie to Mercury, I wonder if there is a more efficient 
implementation supported by the compiler than my version below.

Thanks again,
- Jeff

:- pred bagof(pred(pair(K, V)), K, list(V)).
:- mode bagof(pred(out) is multi, out, out) is nondet.
bagof(Generator, Key, ValueList) :-
   promise_equivalent_solutions([Map], unsorted_aggregate(Generator, 
prependForKey, map.init, Map)),
   map.member(Map, Key, ValueList).

:- pred prependForKey(pair(K, V)::in, map(K, list(V))::in, map(K, 
list(V))::out) is det.
prependForKey(Key - Value, MapIn, MapOut) :-
   if ValueListIn = map.search(MapIn, Key) then
     MapOut = map.set(MapIn, Key, [Value|ValueListIn])
   else
     % MapIn doesn't have Key.
     MapOut = map.det_insert(MapIn, Key, [Value]).



--------------------------------------------------------------------------
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