[mercury-users] 're-creating' higher order insts?

Mark Brown mark at csse.unimelb.edu.au
Mon Oct 8 16:20:11 AEST 2007

On 08-Oct-2007, Ondrej Bojar <bojar at csse.unimelb.edu.au> wrote:
> Hi,
> the chapter of Language Manual on higher-order modes says:
> ---
> In order to call a higher-order term, the compiler must know its 
> higher-order inst. This can cause problems when higher-order terms are 
> placed into a polymorphic collection type and then extracted, since the 
> declared mode for the extraction will typically be `out' and the 
> higher-order inst information will be lost. To partially alleviate this 
> problem, and to make higher-order functional programming easier, if the 
> term to be called has a function type, but no higher-order inst 
> information, we assume that it has the default higher-order function inst 
> `func(in, ..., in) = out is Determinism'.
> ---
> I assume there is no way to reconstruct the lost higher order mode, apart 
> from supplying the higher order mode from outside, e.g.:
> :- type magic_maker == (pred(int))
> :- inst magic_maker == (pred(out) is det).
> :- func construct_magic_maker = (magic_maker::out(magic_maker)) is det.
> :- pred mypred(
>           map(string, magic_maker)::in
>             % plain 'in' because there is no inst map(K_inst, V_inst)
>         ) is det.
> mypred(MagicMakersPerKeyWord) :-
>   KeyWord = "keyword",
>   map.lookup(MagicMakersPerKeyWord, KeyWord, MagicMaker),
>   % MagicMaker is now ground, so it cannot be called
>   FakeMagicMaker = construct_magic_maker,
>   % call FakeMagicMaker instead
>   ...

This is on the right track.  You want something like

:- pred assert_function_is_inst_foo(..., func_type::in, func_type::out(foo))
	is {semi,}det.

Where "foo" is the inst you are expecting at that point in your application.

> Am I correct that in general there is no use of storing a higher order 
> value in an ADT that does not explicitly allow extraction of the higher 
> order value with the correct inst? (E.g. list(T) allows that, because there 
> is inst list(I) and list deconstruction to head and tail honor the 
> instantiatedness.) -- with the exception of functions matching the default 
> mode.
> So in general, I have to store only some ground identifier and have a 
> (assoc_list) mapping from this identifier to the actual predicate. In the 
> example above, the identifier was void (construct_magic_maker had no input 
> argument), so construct_magic_maker could construct a single predicate 
> only.
> Or am I missing something?

The effect of the compiler losing the inst information is that it can't
check statically that the call will be handled correctly.  You are on the
right track in this regard.  What you are missing is that there is a
couple of other options:

1) You can replace the static checking with dynamic checking.  Your
application will have a fixed set of insts that it is interested in, so
you can create a type to describe every possible inst.  Then construct a
value of this type each time you put a function in the ADT, and make sure
you keep track of which value goes with with function (e.g., by packaging
them up in the same term).  You can pass this information in the ... part
of the assert_function_is_inst_foo predicate, above, which can throw an
exception or fail if it is anything other than "foo".

This effectively does for insts what univs do for types, except that the
initial step of creating the inst description is done by the programmer
rather than the compiler.

2) If you are feeling courageous, you can replace static checking with no
checking.  For some purposes this may be safe enough (e.g. if the whole
module only uses one higher-order inst, you aren't so likely to get it
wrong).  It would seg fault if you got it wrong, though.


mercury-users mailing list
Post messages to:       mercury-users at csse.unimelb.edu.au
Administrative Queries: owner-mercury-users at csse.unimelb.edu.au
Subscriptions:          mercury-users-request at csse.unimelb.edu.au

More information about the users mailing list