[m-dev.] a conditional field update operator

Mark Brown mark at mercurylang.org
Wed Mar 8 18:01:50 AEDT 2017


Hi everyone,

On Wed, Mar 8, 2017 at 4:57 PM, Zoltan Somogyi
<zoltan.somogyi at runbox.com> wrote:
> That is part of what I was trying to get at. As you say, conditional assignment
> at any level of a data structure works only if you do it consistently at all the
> levels below it; if you don't, then the new value of a field may be semantically
> equal to the old value, but bitwise different from it. So to apply conditional
> update to the transformation of a whole data structure, you have to do it
> for the transformation of *every part*.

For me, this is the clincher.

The field update syntax can already be redefined to do any checks that
the user wants, including checking a condition before updating. You
can even pass extra parameters in that determine what kind of test you
want and use multiple modes to remove tests at compile time, as in the
example code below. But it won't do the right thing for updates of
nested fields. So I think some new syntax to support conditional
updates of nested fields is warranted.

One question: is this syntax something that can be redefined, like the
existing field syntax, or does it always compile down to calls to the
unconditional field updates (which may themselves be redefined), or
does it always compile to an ordinary construction like the default
field update functions? I vote that it compiles down to unconditional
field updates, viz:

!Term ^ field_list ?= FieldValue

becomes

( if private_builtin.pointer_equal(Term ^ field_list, FieldValue) then
    true
else
    !Term ^ field_list := FieldValue
)

Then this code should call the user defined unconditional field
update, if present.

Mark

--
Example code mentioned above:

:- type s ---> s(
            f1 :: int,
            f2 :: string
        ).

:- type update_when
    --->    always
    ;       ptr_equal.

:- inst always ---> always.
:- inst ptr_equal ---> ptr_equal.

:- func s ^ f2(update_when) := string = s.
:- mode in ^ f2(in) := in = out is det.
:- mode in ^ f2(in(always)) := in = out is det.
:- mode in ^ f2(in(ptr_equal)) := in = out is det.

S ^ f2(When) := Name =
    ( if test_when(When, S ^ f2, Name) then S ^ f2 := Name else S ).

:- pred test_when(update_when, T, T).
:- mode test_when(in(always), in, in) is det.
:- mode test_when(in(ptr_equal), in, in) is semidet.
:- mode test_when(in, in, in) is semidet.

test_when(always, _, _).
test_when(ptr_equal, X, Y) :- private_builtin.pointer_equal(X, Y).


More information about the developers mailing list