[m-users.] How to decompose a term with a variable data constructor
Volker Wysk
post at volker-wysk.de
Tue Nov 2 12:51:43 AEDT 2021
Am Dienstag, dem 02.11.2021 um 04:45 +1100 schrieb Zoltan Somogyi:
>
> On Mon, 01 Nov 2021 18:29:23 +0100, Volker Wysk <post at volker-wysk.de> wrote:
>
> > Hi.
> >
> > I have a simple term type, like this:
> >
> > :- type tterm
> > ---> thema(string)
> > ; und(tterm, tterm)
> > ; oder(tterm, tterm).
> >
> > Now I want to decompose such a term:
> >
> > Konstr(T1, T2) = und(thema("aaa"), thema("bbb"))
> >
> > Konstr is a ground variable, which has been passed as an input argument to
> > my predicate. T1 and T2 are free variables. My idea was that the above
> > statement should succeed if Konstr is "und", and fail otherwise.
>
> It seems you want Konstr to be a sort-of disembodied function symbol,
> with no fixed arity, and able to be applied to an arbitrary number of arguments.
> There is no such construct in Mercury.
>
> > This would
> > mean to pass "und" to the predicate as a function of type (func(tterm,tterm)
> > = tterm). But this won't work.
>
> No, it won't. Your diagnosis of the reason why it wouldn't, i.e. ...
>
> > I realize that the compiler can't unify a function call with a discriminated
> > union. This would mean to calculate the function backwards - the arguments
> > from the result.
>
> ... is correct.
>
> > Now, my question is: How can you decompose a discriminated union when the
> > data constructor isn't known at compile time? Something like
> >
> > Constr(T1, T2) = und(thema("aaa"), thema("bbb"))
> >
> > which would result in
> >
> > Constr = und, % ???
> > T1 = thema("aaa"),
> > T2 = thema("bbb")
>
> If you want to preserve static typing, you would need another type,
> such as this:
>
> :- type tterm_functor
> ---> thema_f
> ; und_f
> ; oder_f.
>
> You could then write something like
>
> ConstrF = und_f, Constr = und(thema("aaa"), thema("bbb"))
>
> This would separate ConstrF, which says which function symbol you want
> for the term you want to construct, from Constr, which would then hold that term.
I've come up with a different solution. For every constructor I have a
construction function and a deconstruction predicate:
:- pred und_deconstruct(tterm::in, tterm::out, tterm::out) is semidet.
und_deconstruct(und(T1,T2), T1, T2).
:- func und_construct(tterm, tterm) = tterm.
func(T1, T2) = und(T1,T2).
... same for oder/2 ...
Now my predicates can be passed one or both of those (as needed). So they
can (de)construct terms without needing to know the the constructor/functor
at compile time.
> If that approach does not work for you, you could consider the deconstruct
> predicate from the deconstruct module of the standard library, but that
> predicate and its friends work on univs, which means that typeckecking
> would be done partially at runtime.
>
> In our experience, the approach using static typing is better in pretty much
> all cases where it is actually applicable. The approach that defers typechecking
> partially to runtime should be used only if there is no other choice.
That doesn't surprise me at all...
Thanks for the explanation.
Cheers,
Volker
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part
URL: <http://lists.mercurylang.org/archives/users/attachments/20211102/1c34b9b6/attachment.sig>
More information about the users
mailing list