[m-dev.] Is this a bug?

Jonathan Morgan jonmmorgan at gmail.com
Mon Jun 18 14:57:30 AEST 2007


On 6/18/07, Peter Schachte <schachte at csse.unimelb.edu.au> wrote:
> Ralph Becket wrote:
> > Ralph Becket, Monday, 18 June 2007:
> >> I'm trying to use field update syntax to update a map of maps, but it
> >> isn't working:
> >>
> >> ::: map_map_update_test.m :::
> >>
> >> :- module map_map_update_test.
> >> :- interface.
> >> :- import_module io.
> >>
> >> :- pred main(io::di, io::uo) is det.
> >>
> >> :- implementation.
> >> :- import_module map.
> >>
> >> main(!IO) :-
> >>     A0 = map.init,
> >>     A  = A0 ^ elem(42) ^ elem(99) := 123,
> >>     io.write_int(A ^ det_elem(42) ^ det_elem(99), !IO),
> >>     io.nl(!IO).
> >>
> >> ::: end of map_map_update_test.m :::
> >
> > Ah, I've understood the problem:
> >
> >       A  = A0 ^ elem(42) ^ elem(99) := 123
> >
> > expands according to the following rule in the reference manual
> >
> >       transform(Term ^ Field(Arg1, ...) := FieldValue) =
> >                       'Field :='(Arg1, ..., Term, FieldValue)).
> >
> >       transform(Term0 ^ Field(Arg1, ...) ^ Rest := FieldValue) = Term :-
> >               OldFieldValue = Field(Arg1, ..., Term0),
> >               NewFieldValue = transform(OldFieldValue ^ Rest := FieldValue),
> >               Term = 'Field :='(Arg1, ..., Term0, NewFieldValue).
> >
> > The OldFieldValue uses the `elem' field access function which is
> > semidet.
> >
> > This is somewhat counterintuitive.
>
> Yes, and a bit annoying to work around.  Just switching to det_elem() won't
> help.  (BTW:  why is the semidet version the default (the one with the
> convenient name)?  Didn't we decide a while back that semidet functions were a
> bad idea?)
>
> The only solution I can think of would be to use a variation on maps that have
> a default value that is returned when looking up an unmapped key.  Elem() would
> be det for that type, so you could use it for the outer map, with default value
> map.init.

If I write something like the following:
    Map = default_map.init(map.init),
    _ = Map ^ elem(42).
and the default value is used, then does Map now have an element 42,
set to map.init?  In either case, I think that the result is a little
strange.  Also, are you expecting the default to be a value, or a
function taking the value of the element we wish to have a default
value for?  The second method is more general, but is also a little
more complicated to use.

All these problems (and more, because of its imperative nature and
lack of a type system) occur with Python's default_map, such that it
is generally advised that users be extremely careful when using it.
On the Mercury side, there is no danger of accidentally adding
additional values to a map when looking up a value, but there is the
potential problem of creating redundant data structures and using more
memory.  In many ways I think that a getter with default values is
more transparent, though not necessarily as nice.  How this integrates
with returning the map altered I'm not really sure.

Jon
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at csse.unimelb.edu.au
Administrative Queries: owner-mercury-developers at csse.unimelb.edu.au
Subscriptions:          mercury-developers-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the developers mailing list