Language interface improvements

Fergus Henderson fjh at cs.mu.oz.au
Wed Nov 19 06:29:48 AEDT 1997


Zoltan Somogyi, you wrote:
> 
> The extended external language interface is really a collection of smaller
> subtasks, and the different subtasks are probaly best approached differently.
[...]
> One of the tools I expect the summer student to write would parse C prototype
> declarations and produce both the declarations and the code for the Mercury
> predicates required to access these. One problem here is the treatment of
> non-builtin data types such as structures; how should these be accessible
> from Mercury? I am sure there are other problems as well, such as that
> some C functions should really have a pair of io__state arguments in their
> Mercury versions whereas others shouldn't, but you are in a much better
> position to point out these problems than we are. (We have access to a
> parser for C written in relatively pure Prolog, so we will probably use
> that as the basis of the tool.)

It might be better to use SWIG ("SoftWare Interface Generator").

> Another tool we can possibly ask the student to write would be generating
> the declarations and code for parsing and unparsing predicates for Mercury
> types. We already support the reading and writing of terms of arbitrary types,
> but only in the natural term notation, e.g. "if(c, t, e)", not in minor
> syntactic variants such as "if c then t else e". A tool that produces
> parsers and prettyprinters that can be easily modified can be useful.

I think an approach based on type classes would be a better solution to
this problem. 

We already have a design for this.  Types which need special
printing should be members of the portrayable/1 type class; that is,
they must have a portray/3 method.  print/3 does a dynamic type-class
membership check to figure out whether the type being printed is a
member of the type class portrayable/1.  If so, it calls the portray/3
method.  Otherwise, it prints the data in the standard syntax
(a la write/3), but recursively calling print/3 to print the arguments.

The work that needs to be done to make this approach work is

	1. implement type classes

	2. implement type-class membership checks

and optionally

	3. implement compiler optimizations so that type-class membership
	   checks etc. are done at compile time rather than at runtime
	   whenever possible.

Most of step 3 can be done in parallel with 1 & 2.

> Do you, or Paul or Renaud, have any other suggestions for improving the
> external language interface?

I have some suggestions.

1.  Add `pragma import'.  This is the inverse of `pragma export'.
    It is similar to `pragma c_code' except that you specify
    only a function name, rather than a C code fragment.
    The Mercury compiler automatically constructs the C code
    fragment by inserting the parameters.  For example, if
    we have the following Mercury declarations,

	:- pred mp(int::in, int::out, float::in, float::out) is det.
	:- pred mf(int::in, float::in) = (float::out) is det.

    then these `pragma import' declarations

	:- pragma import(mp(in, out, in, out), "cp").
	:- pragma import(mf(in, in) = out, "cf").

    would be equivalent to the (more verbose) declarations below:

	:- pragma c_header_code("
		void cp(int, int *, float, float *);
		float cf(int, float);
	").
	:- pragma c_code(mp(A::in, B::out, C::in, D::out), "
		cp(A, &B, C, &D);
	").
	:- pragma c_code(mf(A::in, B::in) = (C::out), "
		C = cf(A, B);
	").

2.  Allow `p/4' as an alternative to `p(in, out, in, out)'
    in `pragma export' declarations,
    in the case where p/4 has only one mode.
    Similarly, allow `p(A, B, C, D)' as an alternative to
    `p(A::in, B::out, C::in, D::out)' in `pragma c_code'
    declarations, in the case where p/4 has only one mode.

These ideas have both been around since before we first started implementing
the C interface; they were left out of the stuff we actually implemented
only because DJ's time was finite.  We knew that ideally we wanted both
`pragma c_code' and `pragma import', but to simpify things we just
settled for one of these (and for performance reasons, it was the former).
Similarly, when deciding between `p(in, out)' and `p/2', for simplicitly
we settled for just one (and it had to be the former, because it is more
general), even though the ideal solution would to provide both, so that
the programmer can get conciseness if the full generality isn't needed.

Cheers,
	Fergus.

-- 
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 developers mailing list