[mercury-users] Mercury interface for nondet predicates

Julien Fischer juliensf at csse.unimelb.edu.au
Mon Jan 31 16:18:46 AEDT 2011


Hi,

On Sun, 30 Jan 2011, Jeff Thompson wrote:

> I've been enjoying a lot of success with the csharp grade.  Now for the next 
> step: I want to interface from C# to a nondet predicate by setting up the 
> query, then asking for each result.  I want to use this for database-like 
> applications where there may be many results.
>
> What is the recommended way to do this?  Looking at the generated C# code, 
> perhaps I need to create the environment structure for the predicate?

Nondet and multidet code are not directly supported by the foreign
language interface; the recommended iway of interfacing foreign language
code to nondet code is to put a det wrapper around it (using one of the
all-solutions predicates from the standard library) and call that from
the foreign language; if you need to then call the foreign language to
process each solution use solutions.do_while/4.

I have attached an example program that does this when using C as a
foreign language -- the C# would be similar modulo the obvious
differences between C and C#.  To build, do:

     $ mmc --make test_foreign_call_multi

in one of the C grades.  (The top-level of this program is C embedded 
inside Mercury; that's purely a matter convenience - the same thing would 
work when calling the nondet / multidet Mercury predicate from a real C
or C++ program.)

> I read the following link "Calling Mercury code from C" but doesn't seem to 
> cover multi predicates:
> http://www.mercury.cs.mu.oz.au/information/doc-latest/reference_manual_14.html#SEC124

I don't think that page should be there; it appears as though there are
some old HTML files there that weren't cleaned up.

Cheers,
Julien.
-------------- next part --------------
%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%

:- module foreign_call_multi.
:- interface.

%-----------------------------------------------------------------------------%

    % Shut up warnings about nothing being exported.
    %
:- type suppress_warnings
    --->    suppress_warnings.

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%

:- implementation.

:- import_module bool.
:- import_module io.
:- import_module solutions.

%-----------------------------------------------------------------------------%

    % A multi-deterministic predicate such as this cannot be called directly
    % from foreign language code ...
    %
:- pred query(int::out) is multi.

query(1).
query(2).
query(3).
query(4).
query(5).
query(6).

%-----------------------------------------------------------------------------%

    % ... instead we have to interface with the multi predicate via some
    % deterministic (or in this case cc_multi) code.
    %
    % The first argument of do_query/3 is a C function pointer that is called
    % when a solution to query/1 is generated with the solution being passed as
    % the argument to the C function called via the function pointer.
    % (The C function, in this example, returns a Boolean that says whether
    % we should continue searching for solutions or not.)
    %
    % To search for solutions we use the predicate do_while/4 from the solutions
    % module in the standard library.
    %
:- pred do_query(c_query_handler::in, io::di, io::uo) is cc_multi.

    % Export do_query/3 to C.
    %
:- pragma foreign_export("C", do_query(in, di, uo), "EXPORTED_do_query").

do_query(C_Handler, !IO) :-
    % Generate all solutions to query/1 and invoke handle_query/5 on each one.
    do_while(query, handle_query(C_Handler), !IO).

    % This predicate just calls the C function pointed to be its first
    % argument.
    %
:- pred handle_query(c_query_handler::in, int::in, bool::out, io::di, io::uo)
    is det.

:- pragma foreign_proc("C",
    handle_query(Handler::in, V::in, Continue::out, _IO0::di, _IO::uo),
    [promise_pure],
"
    Continue = (Handler(V)) ? MR_YES : MR_NO;
").

%-----------------------------------------------------------------------------%

    % A C function pointer type
:- type c_query_handler.

:- pragma foreign_decl("C", "

typedef int (*c_handler_type)(int);

").

    % NOTE: Mercury doesn't allow function pointer types to be used directly
    % in foreign_type pragmas - so we need to use the above typedef here.
    %
:- pragma foreign_type("C", c_query_handler, "c_handler_type").

%-----------------------------------------------------------------------------%
:- end_module foreign_call_multi.
%-----------------------------------------------------------------------------%
-------------- next part --------------
%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%

:- module test_foreign_call_multi.
:- interface.

%-----------------------------------------------------------------------------%

:- import_module io.

:- pred main(io::di, io::uo) is det.

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%

:- implementation.

:- import_module foreign_call_multi.
:- pragma foreign_import_module("C", foreign_call_multi).

%-----------------------------------------------------------------------------%

main(!IO) :-
	do_main(!IO).

:- pred do_main(io::di, io::uo) is det.

:- pragma foreign_proc("C",
	do_main(_IO0::di, _IO::uo),
	[promise_pure],
"
    EXPORTED_do_query(my_query_handle);
").

:- pragma foreign_decl("C", "

#include <stdio.h>

extern int
my_query_handle(int v);

").

:- pragma foreign_code("C", "

int
my_query_handle(int v)
{
	printf(\"Query result: %d\\n\", v);
	return 1; 
}

").

%-----------------------------------------------------------------------------%
:- end_module test_foreign_call_multi.
%-----------------------------------------------------------------------------%


More information about the users mailing list