[m-users.] Issue with assoc_list and other container types

Peter Wang novalazy at gmail.com
Thu Jan 20 10:56:45 AEDT 2022


On Wed, 19 Jan 2022 21:01:16 +0100 Volker Wysk <post at volker-wysk.de> wrote:
> Hi!!
> 
> The search predicate in the assoc_list module is like this:
> 
> :- pred search(assoc_list(K, V)::in, K::in, V::out) is semidet.
> 
> This leads to a problem. The mode of the output variable is "out", this
> means that its instantiation state is "ground", after the predicate has been
> called. I have a "call_action" predicate like this:
> 
> :- inst assoc_list(K, V) == list(pair(K, V)).
> 
> :- func actions =
>     ( assoc_list(string, pred(string, string))
>       :: out(assoc_list(ground, pred(in, out) is det))
>     ).
> 
> :- pred call_action(string::in, string::in, string::out) is det.
>     
> call_action(Action, Str, Str1) :-
>     (
>         if   assoc_list.search(actions, Action, Pred)
>         then Pred(Str, Str1)
>         else throw("Bug: unknown action " ++ Action)
>     ).
> 
> The variable "Pred" gets the instantiatedness "ground". This means that
> "Pred(Str, Str1)" leads to a compile time error, because the
> instantiatedness of Pred needs to be "pred(in, out) is det" for the call.
> And such a higher-order inst is not ground.
> 
> This means that functions/predicates can't be usefully stored in association
> lists, because you can't call them (what else would you want to do with
> them?).

The workaround (or preferred pattern, if you like) is to define a type
to carry the higher-order inst around:

    :- type action_pred
        --->    action_pred(
                    pred(string::in, string::out) is det
                ).

Then store values of that type in your container instead of the
higher-order terms directly.

> 
> :- pred assoc_list_search(
>     assoc_list(string, pred(string, string)),
>     string,
>     pred(string, string)).
> 
> :- mode assoc_list_search(
>     in(assoc_list(Key, Val)),
>     in,
>     out(Val))
> is semidet.
> 
> assoc_list_search(L, K, V) :-
>     ( L = [K - V]
>     ; L = [_, K1 - V1 | Rest],
>       assoc_list_search([K1 - V1 | Rest], K, V)
>     ).
> 
> This predicate works for call_action/3. You get the higher-order-inst of the
> predicate, which has been found, in the search result. 
> 
> I guess, the assoc_list.search/3 and other predicates/functions should be
> modified, and it be done this way.
> 
> It should be the same problem with other container types (I haven't
> checked).

This works for assoc_list because the type definition is exported from
the module. It won't work for types like types like map where the type
is deliberately kept private.

Peter


More information about the users mailing list