[m-users.] Higher order type with existential quanitfication

Volker Wysk post at volker-wysk.de
Mon Oct 23 21:23:22 AEDT 2023


Am Montag, dem 23.10.2023 um 20:53 +1100 schrieb Zoltan Somogyi:
> On 2023-10-23 20:19 +11:00 AEDT, "Volker Wysk" <post at volker-wysk.de> wrote:
> > Does that mean, that it's impossible to define a map_hetlist predicate like
> > this:
> > 
> > :- type hetlist
> >     ---> some [T] hetcons(T, hetlist)   => att(T)
> >     ;    hetnil.
> > 
> > % declaration of map_hetlist?
> > 
> > map_hetlist(_, hetnil, []).
> > 
> > map_hetlist(Pred, hetcons(X, L), [Y|Ys]) :-
> >     Pred(X, Y),
> >     map_hetlist(Pred, L, Ys).
> 
> I cannot answer your question, because I don't know for sure what you intend
> this code to do. The code tells me one thing about your intentions;
> your description tells me another.

I have a database application and made semantic wrappers for the attributes
of my database tables. I wanted to be able to pass a list of such attributes
to, for instance, a generic "select" predicate. So I wanted to put them in a
heterogenous list. The attributes have typeclass member functions for
converting the wrapped value to SQL, and similar things.

> 
> If you mean "can I give meaning to that exact code", yes, I can, but I don't know
> whether it is the meaning you INTENDED to give that code. Also, Mercury
> can't implement my meaning.
> 
> In that code, Pred has to be an input of map_hetlist, because it is
> used as the predicate to call. The second argument, the hetlist, is similar
> to a list of univ in that each element may have a different type. It is different
> from a list of univs in that you know that each of those types is a member
> of the att type class. Since this is all you know about the elements of the hetlist,
> the only things Pred can do with X are
> 
> - call the operations of the att typeclass,
> - call operations that work on values of *any* type, such as string.string.
> 
> And of course Pred can do those things in any combination it likes.
> I can accept that as the meaning of those code. However, Mercury can't do so.

Your meaning is correct. That's what I'm trying.

> 
> The problem, as you discovered, is that there is no way in Mercury to type
> the first argument of Pred in your code. This is why map_hetlist_a below,
> which is effectively your code, gets an error from mmc.
> 
> The version map_hetlist_b below, which is what I am recommending,
> avoids this error by making the type of the first argument of Pred
> just a defined type. This sidesteps the problem, and the compiler accepts this version.
> 
> Zoltan
> 
> :- module y.
> 
> :- interface.
> 
> :- import_module list.
> 
> :- typeclass att(T) where [].
> 
> :- type hetlist
>     --->    some [T] hetcons(T, hetlist) => att(T)
>     ;       hetnil.
> 
> :- pred map_hetlist_a(pred(X, Y), hetlist, list(Y)).
> :- mode map_hetlist_a(in(pred(in, out) is det), in, out) is det.
> 
> :- type hetunit
>     --->    some [T] hetunit(T) => att(T).
> 
> :- pred map_hetlist_b(pred(hetunit, Y), list(hetunit), list(Y)).
> :- mode map_hetlist_b(in(pred(in, out) is det), in, out) is det.
> 
> :- implementation.
> 
> map_hetlist_a(_, hetnil, []).
> map_hetlist_a(Pred, hetcons(Head, Tail), [Y | Ys]) :-
>     Pred(Head, Y),
>     map_hetlist_a(Pred, Tail, Ys).
> 
> map_hetlist_b(_, [], []).
> map_hetlist_b(Pred, [Head | Tail], [Y | Ys]) :-
>     Pred(Head, Y),
>     map_hetlist_b(Pred, Tail, Ys).

A moment ago, I found a different solution:

:- type wrp ---> some [T] wrp(T) => att(T).

:- pred map_hetlist(
    pred(wrp, Y)::in(pred(in, out) is det),
    hetlist::in,
    list(Y)::out)
is det.

map_hetlist(_, hetnil, []).

map_hetlist(Pred, hetcons(X, L), [Y|Ys]) :-
    Wrp = 'new wrp'(X),
    Pred(Wrp, Y),
    map_hetlist(Pred, L, Ys).

But your map_hetlist_b is preferable, because it doesn't need a heterogenous
list. A normal list can be used and all the list operations from the
standard library are available.

Thanks!
Volker


More information about the users mailing list