[m-dev.] Suggested interface for sequence types in lib-v2

Fergus Henderson fjh at cs.mu.OZ.AU
Sat Oct 21 02:22:38 AEDT 2000


On 20-Oct-2000, Ralph Becket <rbeck at microsoft.com> wrote:
> > > :- func but_last(seq(T)) = seq(T).
> > > :- func semidet_but_last(seq(T)) = seq(T) is semidet.
> > 
> > What is that supposed to do?
> 
> These are supposed to return all but the last member of a
> sequence,

Ah!  OK, that makes sense.

I think `all_but_last' would be a much clearer name.

> The intended meaning is important for double-ended sequence
> types.

Yes, agreed.

> > > :- pred project_member(seq(T)::in, T::out) is nondet.
> > 
> > What is that supposed to do?
> > How does it differ from `member'?
> 
> Several `solutions' style predicates expect the output argument
> to be the last one.

OK, I see.  Yes, for historical reasons `member' goes against our
usual style guidelines about argument ordering.

The name `project_member' doesn't mean much to me.
I think `has_member' or perhaps `contains_member' would be a better
name.  It would work nicely with infix syntax:

	List `has_member` Elem

> I included project_member/2 for this
> reason.  It's debatable whether or not it's useful enough to
> warrant inclusion, but if we supply the obvious default
> implementation based on member/2 then we should be okay.

Only one of member/2 and project_member/2 (or has_member/2)
should be a class method.  The other should just be an
ordinary procedure with a class constraint on its type.
This ensures that the relationship between the meaning
of these two always remains unchanged.

> > > :- func rev_append(seq(T), seq(T)) = seq(T).
> > 
> > What is that supposed to do?
> 
> 	rev_append(S1, S2) = reverse(S1) ++ S2

OK.  The original documentation has a lot of room for improvement ;-)

> > >                                         % XXX Is this really useful?
> > > :- func condense_map(func(T1) = seq(T2), seq(T1)) = seq(T2).
> > 
> > Is this just
> > 
> > 	condense_map(F, S) = condense(map(F, S)).
> > 
> > ?
> > If so, I don't think it is worth including, unless there
> > are some sequences for which condense_map(F, S) can be implemented
> > more efficiently than condense(map(F, S)).  Off-hand I don't know
> > of any such sequences.
> 
> condense_map/2 is there to avoid construction of an intermediate
> sequence.

I don't think this is likely to be useful enough to warrant inclusion.
I'd leave it out for now.  We can always add it later if it turns
out to be widely needed.

> > > % REMOVING MEMBERS
> > > 
> > >                                         % Error unless S `contains` X.
> > > :- func delete_first(T, seq(T)) = seq(T).
> > 
> > I think that should be semidet.
> > A det `delete_first_det' might be useful, but
> > I think the semidet one is probably more useful.
> 
> Okay.  The convention I was using was that operation foo would be
> det while semidet_foo would be semidet.  In this case it's not
> clear whether the proper functionality is to delete the first
> x if one is present, otherwise do nothing.  Hmmm...

In most situations where you want that functionality ("otherwise do
nothing"), `delete_all' will do.  So I think `delete_first_det' should
call error/1 if the element isn't present.

> > > % INDEX BASED OPERATIONS
> > >                                         % index_in(S, head(S)) = 0.
> > > :- func index_in(seq(T), T) = int.      % Error unless S `contains` X.
> > > :- func semidet_index_in(seq(T), T) = int is semidet.
> > 
> > Our traditional naming scheme for these kind of things has been
> > for the semidet one to have the unadorned name, and for the
> > det one to get a `_det' suffix.  I think this is a better idea,
> > since the explicit `_det' suffix serves as a hint that the procedure
> > might call error/1 in some circumstances, and so the programmer
> > had better be careful to ensure that the parameters at each call
> > meet the preconditions.
> 
> I think that is true for predicates, but that the reverse should
> be the case for functions.  After all, one usually expects a function
> to be deterministic.

Hmm, good point.

> I'm prepared to be converted on this one...
> anybody else have any strong feelings?

I'd be very interested in other people's views on this one.

> > So is change(S, I, F) = replace(S, I, F(S `lookup` I))?
> > If so, then (a) that would be a simpler way of documenting it
> > and (b) is it really worth including in the standard library?
> 
> I've changed the comment to (a).  The question here is
> whether or not there are enough random-access sequence types for
> which there are more efficient implementations than the RHS to
> justify the inclusion of change/3.
> 
> The jury may still be out on this one, but for, say, bt_arrays and
> maps change/3 would be handy and more efficient.

Oh, I see.  That sounds quite reasonable.
Maps are very widely used, so it's worth including this.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list