[m-rev.] for review: state vars syntax sugar

Julien Fischer juliensf at csse.unimelb.edu.au
Thu Feb 1 01:48:16 AEDT 2007


On Wed, 31 Jan 2007, Peter Schachte wrote:

> Julien Fischer wrote:
>
>> Going back to the above proposal (and since we seem to be optimising for
>> the common case), there's a fairly good argument for making !(X) mean
>> unique >> dead, free >> unique given that probably the most common use
>> for state varaibles is for threading the I/O state.
>
> I would expect they'd also be used for all kinds of accumulators, like
> counters, lists, etc, which would mostly be ground, not unique.

Even taking all that into account I suspect threading the I/O state is still
the one of most common use of state variables.  (A quick grep through
the compiler for counts "X::in, X::out" for various X that are commonly
used with state variables vs. io::di, io::uo seems to back this up - at
least for the compiler).

>>> The conceptual shift is that you think of a state variable !Var as
>>> specifying a value that changes throughout the execution of the clause,
>>> rather than as a different pair of variables every place it appears,
>>> with the variables threaded together in a certain way.  Then !.Var
>>> denotes the current value, and !:Var specifies a new value, for that
>>> state variable.
>>
>> I don't think of state variables that way: they are a sequence of values,
>
> That sounds pretty much like what I'm saying.  So if you see !Var as a sequence
> of values, why do you want to think of it in terms of the implementation as
> pairs of variables?  And if you're not thinking of it as pairs of variables,
> why do you want to be forced to think of pairs of modes?
>
>>> With that view, it makes sense for it to have a single type and a
>>> single, consistent instantiation state (rather than the confusion of 4
>>> instantiation states).
>>
>> Even leaving uniqueness aside I don't see that there needs to be a single
>> instantiation state.  It is perfectly reasonable for subtype information
>> to be change through a sequence of operations (and the type to remain
>> unchanged).
>
> ... Just as the type may change through a sequence of operations.  But we're
> just discussing syntactic sugar; it should handle the common cases elegantly
> and succinctly.  Other cases can be handled in unsweetened form.  How many
> predicates have you written using state variables that change instantiation as
> they evolve?

Not that many at the moment; the extra work required to workaround
limitations in the current mode analyser's support for subtyping makes it too
much work.  If that weren't the case I could see myself using them more.

>>> So let's compare the proposals.  The current proposal, as I understand
>>> it:
>>>
>>>     pred declarations:    !type specifies types of two arguments
>>>     mode declarations:    no support; must specify two modes
>>
>> Not quite, you can specify (mode, mode) in the list of modes but it is just
>> flattened out.
>
> OK, so you can write parentheses around an adjacent pair of modes.  This has no
> semantics, just some documentation value.  But since the compiler can't check
> it in any way, it's not reliable documentation.  That's why I prefer the idea
> of allowing Type::(Mode1, ..., Moden) as an abbreviation for Type::Mode1, ...
> Type::Moden:  at least it doesn't appear to have a semantics the compiler
> cannot check at all.  It's also more useful.
>
>>>     predmode declarns:    !Type::(Mode, Mode)
>>
>> To which you can add:
>>
>>      typeclass method decls of various sorts - as above
>>      lambda expressions
>>      mode-specific clauses
>>      foreign_export pragmas - maybe
>
> AFAICS, these are all covered by the syntax I proposed.  I'll comment on
> lambdas below.
>
>>>     Note that nothing stops you from writing, eg:
>>>
>>>         :- pred append(!list(T), list(T)).
>>>         or    :- pred append(!list(T)::(in, in), list(T)::out).
>>
>> In that case the difficulty of writing the corresponding clauses
>> for append with that particular arrangment of state variables might
>> soon give me pause for thought.
>
> Not at all.  The compiler would accept this with your preferred syntax:
>
> 	:- pred append(!list(T)::(in, in), list(T)::out) is det.
>
> 	append([], !V).
> 	append([H|T], !V) :-
> 		append(T, !V),
> 		!:V = [H|!.V].

Yep, although putting the state variables in the wrong spot is a
potential problem even with the existing syntax; I don't remember it
ever coming up in practice.

> The equivalent of that pred declaration with my proposal would be:
>
> 	:- pred append(!list(T)::ground, list(T)::out) is det.
>
> which the compiler would not accept because the mode doesn't match the code.
> My syntax is more restrictive, so it would catch more errors.

You can abuse most syntax if you try hard enough, e.g.

 	:- pred foo(!list(T)::ground, !list(T)::ground) is det.

 	foo(!.X, !:Y, !.Y, !:X) :-
 		....

doesn't really correspond to the spirit of what you are proposing.
and yet your proposal doesn't disallow that.

> Personally, I'd advocate allowing state variable notation in clause heads
> only where they're declared in pred declarations, and vice versa.

That's a little unclear.  What happens in the situation where there
is a single state variable in the clause head rather than a state
variable pair?

 	:- pred foo(counter::in, T::in, T::in, T::out) is det.

 	foo(!.C, X, Y, Z) :-
 		do_something(X, !C),
 		do_something(Y, !C),
 		do_something_else(Z, !.C).

(For that matter since you insist that state variable pairs are
a single value how do you interpret the above?)

Also, if as you suggest, state variable notation in a clause head
must have a corresponding declaration in the pred decl then which
of the proposed syntaxes are you proposing to use: yours adds a bunch
of restrictions that aren't currently there.  Now we can't even
express the corner cases that the unsugared syntax allows.

>> Previously (and in the current proposal), :: is always followed by a mode
>> or a 2-tuple of modes, with your proposal I now have to switch my
>> thinking between modes and insts depending on whether the argument I'm
>> looking at is a state variable pair or not
>
> Yup.  With your approach, the right side of a :: could be one mode or two,
> ie, two insts or four.  With my approach, it's two insts or one.

Modes and insts are distinct at the syntatic level, with your approach
it is one *mode* or one *inst*.  (At the very minimum I would want the
operator before the inst to be something other than :: ).

...

> With your approach, you have to specify the modes of
> the two arguments that you are forced to think of state variables as; with
> mine, you specify the inst that each value of the state variable must
> have.

State variables are two arguments.  What would you say the arity of the
following clause is?

 	p(A, B, !C).

(If your answer is three then you'll find compiler disagreeing with you
when you try to attach a pragma to it that explicity mentions the arity.)

>> Actually, what I'm looking for is way of simplifying the state variables
>> in the heads of labmda expressions, e.g.
>>
>>
>>      P = (pred(X::in, !IO::(di, uo)) is det :-
>>          ...
>>      )
>
> Easy peasy:  P = (pred(X::in, !IO::unique) is det :- ... )

I wasn't claiming that it would be difficult with your proposal, merely
showing where I think a more concise state variable syntax would
be useful - the point of about lamda expressions was getting a little
lost under all the discussion about predmode declarations and alike.

For something a little less easy peasy:

 	DeleteBars = (pred(!X::(in(list_skel(foo_or_bar)), out(list_skel(foo)))
 			is det :-
 		...
 	)

And I don't see why I should be forced to use the unsugared version just
because I'm doing something a little unusual with the insts here.  IMO,
the above is an improvement over what I am currently required to put
(and what your proposal requires me to put).

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



More information about the reviews mailing list