[m-users.] Concise syntax for initialising and updating discriminated union types

Sean Charles (emacstheviking) objitsu at gmail.com
Tue Jul 19 02:55:31 AEST 2022


I too have had similar thoughts, but in the end I settle for what already exists.

For any DU type I have a 'default' constructor function e.g. this one from my literate programming tool :-

:- func pstate_init(string::in) = (pstate::out) is det.

pstate_init(Filename) = pstate(
    Filename,                       % For errors
    skip_text,                      % Initial parse state
    0,                              % Pandoc size open/close filter
    plain_text(-1, ""),             % Last fence header seen
    no,                             % Current block name scanned
    no,                             % Last block name scanned
    map.init : codeblock_map,       % Named blocks collection
    [],                             % current block content
    []                              % Error messages
).

If I find myself updating two or three fields one after the other more than once then I just abstract it away into a predicate so it's following DRY, and if one is really concerned with performance then you can 'inline' it by I don't go that far.

TBH I quite like the way Mercury --insists-- that I do things by the book, there is a stark unyielding beauty to the way it makes you write your code in certain ways, and coupled with the fact I never go over column 79, it reminds my of the good old days of a VT220!




> On 18 Jul 2022, at 17:50, Volker Wysk <post at volker-wysk.de> wrote:
> 
> Hi!
> 
> There are two things which occur to me every now and then, about working
> with discriminated union types with field names.
> 
> 1. How to initialise a value of a discriminated union type, by using field
> names (similar to the way they can be used for field access and field update
> functions)?
> 
> I find myself defining a "null" value, which is initialised without usage of
> field names. But this is error prone. Afters, I change fields of that null
> value to get my value.
> 
> This leads to point no. 2:
> 
> 2. How to concisely update multiple fields? You can do this in multiple
> steps, like this:
> 
> konstr1(LP3) :-
>    LP1 = 'lp_link_target :='(null_link_parts, "Target"),
>    LP2 = 'lp_link_subsection :='(LP1, yes("Subs.")),
>    LP3 = 'lp_link_text :='(LP2, "bla").
> 
> But this too, is rather verbose and maybe error prone.
> 
> The code smells very much like state variables. It could be done like this:
> 
> konstr3(Out) :-
>    some [!LP] (
>        !:LP = null_link_parts,
>        lp_link_target("Target", !LP),
>        lp_link_subsection(yes("Subs."), !LP),
>        lp_link_text("bla", !LP),
>        Out = !.LP
>    ).
> 
> For this, there need to be defined field update predicates:
> 
> lp_link_target(Val, In, Out)     :- Out = 'lp_link_target :='(In, Val).
> lp_link_subsection(Val, In, Out) :- Out = 'lp_link_subsection :='(In, Val).
> lp_link_text(Val, In, Out)       :- Out = 'lp_link_text :='(In, Val).
> 
> 
> So there are two things that I'm missing. 
> 
> 1. A concise syntax for initialising values of a discriminated union type.
> Something like this (link_parts is a data constructor):
> 
> link_parts(lp_link_target = "Target",
>           lp_link_subsection = yes("Subs."),    
>           lp_link_text = "bla").
> 
> The compiler would complain when some fields aren't initialised.
> 
> 2. Some concise way to update multiple fields, like above. Maybe the
> compiler could additionally generate field update predicates for the fields
> (like above), similar to field update functions.
> 
> 
> Cheers,
> Volker
> _______________________________________________
> users mailing list
> users at lists.mercurylang.org
> https://lists.mercurylang.org/listinfo/users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurylang.org/archives/users/attachments/20220718/aed6193b/attachment.html>


More information about the users mailing list