[m-users.] Question regarding predicates stored in existential data types.

Peter Wang novalazy at gmail.com
Sat Feb 20 17:04:01 AEDT 2021


On Thu, 18 Feb 2021 18:04:15 -0500 Philip White <philip at pswhite.org> wrote:
> 
> Nice! That does make the compiler happy and allow me to use [in] and
> [out], happily. Followup question:
> 
> I have the following interface provided by a module:
> 
> :- type error.
> :- func error_to_string_hum(error) = string.
> :- type eval_result(T) ---> ok(T) ; error(error).
> :- pred eval_args(command(T), list(string), eval_result(T)).
> :- mode eval_args(in, in, out) is det.
> 
> The typical case is that the T parameter to a command is some
> predicate. However, after calling eval_args and extracting the
> predicate from the result, I'm having trouble invoking it. Here is my
> entire main module:
> 
> main(!IO) :-
>     io.command_line_arguments(Args, !IO),
>     Command = comm.of_flag(
>         "The command documentation",
>         comm.map(
>             comm.flag("The first flag you need to pass", "first", comm.int),
>             pred(First::in, Result::out) is det :-
>                 Result = ( pred(!.IO::di, !:IO::uo) is det :-
>                     io.write_string("inside command", !IO),
>                     io.write(First, !IO),
>                     io.nl(!IO)
>                 )
>         )
>     ),
>     comm.eval_args(Command, Args, CommandValue),
>     (
>         CommandValue = ok(Pred),
>         Pred(!IO)
>     ;
>         CommandValue = error(Error),
>         io.write(Error, !IO)
>     ),
>     io.nl(!IO).
> 
> There error I'm getting is that Pred has instantiatedness ground but a 
> higher-order pred inst was expected. I think I understand why, based on
> the preceding discussion, but I'm not sure what a good solution is here.

Remember that mode out == free >> ground, so the eval_result(T) argument
will be ground at the end of eval_args. When you deconstruct a ground
term, any sub-terms will also be ground.

To reiterate, you can't call a higher order term with a ground inst
because there is no information to say which arguments are inputs or
outputs, or what the determinism is, or what the purity is.
These have to be known statically.

The original intention of the language was that you would not use 'out'
for the result of eval_args, but a mode free >> complicated_inst,
where complicated_inst is something like ground_flag which you defined,
that does include higher order insts.

You can still do that. However, in/out modes are too convenient, and
using complicated insts is too inconvenient. That is why we introduced
the feature where you can include higher order *inst* information in a
discriminated union *type* definition. Unfortunately, the inst
information isn't yet being used by the compiler when you deconstruct a
constructor with existentially quantified type variables.

(In future, it may be possible to allow higher order insts in other
places where types are specified, but no one is working on it, and
it is probably quite tricky.)

> Perhaps wrapping the function in a single-case variant would work here,
> but that seems tedious to do every time I want to define a new command.

It's true that higher order programming in Mercury is not the most
convenient.

Peter


More information about the users mailing list