[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