[m-users.] Calling type constructors from C

Julien Fischer jfischer at opturion.com
Wed Jul 10 19:26:18 AEST 2019


Hi Sean,

On Wed, 10 Jul 2019, emacstheviking wrote:

> Any clues in the documentation as to where I can find out how to do
> this? I've looked (and failed) to figure out how to call "maybe(T)"

You don't call maybe(T), in this case you are attempting to construct
it.

> from C, basically I have the result of calling a C function that
> reutns NULL or a window pointer:
>    SDL_WIndow *w = SDL_CreateWindow(...);
> 
> and I want the pred to return maybe(sdl_window) where so in my main code I can switch on the result blah blah
> 
> sdl_creatwindow(..., MW, ..., !IO),
> (
>     MW = yes(Wnd),
>     % start my app
> ;
>     MW = no,
>     % fail path
> ),
> 
> 
> :- type sdl_window.
> :- pragma foreign_type("C", sdl_window, "SDL_Window *", [can_pass_as_mercury_type]).
> 
> It's just knowing what the "way" is?!?!

The two usual approaches here would be:

1. Export a Mercury function to C that wraps the result of
SDL_CreatWindow and call that from within the foreign_proc for
sdl_createwindow.  E.g.

    :- pragma foreign_export("C", maybe_yes_window(in) = out,
        "MER_maybe_yes_window").
    :- func maybe_yes_window(sdl_window) = maybe(sdl_window).
    maybe_yes_window(W) = yes(W).

    :- pragma foreign_export("C", maybe_no_window = out,
       "MER_maybe_no_window").
    :- func maybe_no_window = maybe(sdl_window).
    maybe_no_window = no.

    :- pragma foreign_proc("C",
       sdl_createwindow(... MW::in, ... _IO0::di, IO::uo),
       [will_call_mercury, promise_pure],
    "
       SDL_Window *w = <<create the window>>;
       if (w == null) {
          MW = MER_maybe_no_window();
       } else {
          MW = MER_maybe_yes_window(w);
       }
   ").

NOTE: since sdl_createwindow will make calls back to Mercury the
'will_call_mercury' foreign code attribute must be set on the foreign
proc.

2. Return an additional flag indicating if the window pointer is null or
not.

   sdl_createwindow(..., MW, ..., !IO) :-
     do_createwindow(..., IsNull, W, !IO),
     (
          IsNull = no,
          MW = yes(W)
     ;
          IsNull = yes,
          MW = no
     ).

   :- pred do_createwindow(..., bool::out, sdl_window::out,
     io::di, io::uo) is det.
   :- pragma foreign_proc("C",
       do_create_window(..., IsNull::out, W::out, _IO0::, _IO::uo),
       [will_not_call_mercury, promise_pure],
   "
      W = <<create the window>>;
      IsNull = (W == null) ? MR_YES : MR_NO;
   ").

Julien.


More information about the users mailing list