[e-lang] scoping rules of when-catch
David Hopwood
david.nospam.hopwood at blueyonder.co.uk
Sun Jul 23 15:44:30 EDT 2006
Mark S. Miller wrote:
> David Hopwood wrote:
>
>> # This means that the user defined __if and __while constructs can
>> # properly simulate the built-ins (except that the built-in 'while'
>> # can magically bind __break and __continue, though the user-defined
>> # __while cannot).
>>
>> What changes would be necessary to lambda-args to make exit constructs
>> like 'break' and 'continue', and similar constructs for user-defined
>> control abstractions, work correctly?
>
> I think the answer must be "they can't". If they could, the whole
> rationale for user-defined control constructs
> <http://www.erights.org/data/irrelevance.html> would be violated.
> User-defined control constructs must be scope analyzable by the
> programmer when looking at a use occurrence without looking up or
> needing to know the defining occurrence.
'break' and 'continue' don't violate scope analyzability because each
'for' and 'while' loop *always* implicitly defines these names. So, when
you see a 'break' or 'continue', you can apply the scope analysis rules
as though explicit 'break' and 'continue' definitions had been added to
each looping control construct, like in the example you give:
> A while construct like
>
> __while (condExpr) fn __break, __continue { bodyExpr }
>
> would work, since the defining occurrences of __break and __continue
> appear explicitly.
The same would be true of user-defined control constructs provided
that we can tell precisely which constructs should be analyzed in
this way.
Suppose we define a construct 'control' so that, for example,
control myConstruct (condExpr) { bodyExpr }
==> __myConstruct (condExpr) fn __break, __continue { bodyExpr }
(As you mention below, this is not quite right as regards the scope
of __break, but that is fixable.)
Then, although 'for' and 'while' would still have to be built-in, their
expansions would become trivial:
while (condExpr) { bodyExpr }
==> control __while (condExpr) { bodyExpr }
for kPattern => vPattern in collExpr { bodyExpr }
==> control __for (kPattern, vPattern, collExpr) { bodyExpr }
(well, the latter would work if patterns were first-class, anyway).
I.e. the "magic" is restricted to the 'control' construct, whose purpose is
only to add definitions of 'break' and 'continue', and nothing else. To
me this approach would be less magical.
> With pragma.enable("lambda-args") turned on, this
> expands to
>
> __while.fn__control_1_2(fn{
> [[condExpr], fn __break, __continue { bodyExpr }]
> }).run__control()
>
> In the mangled verb name sent to __while, the "1" is the arity of the
> parenthesized expression list following the __while. The "2" is the
> arity of the function representing the body of that clause.
<aside> This mangling is rather ugly. There must be a better way. </aside>
> The __while
> in the current E library does not currently respond to
> "fn__control_1_2", and I doubt we will extend it to do so. Instead,
> because of this issue, I expect the "while", "for", and "to" expansions
> to remain built in.
>
> Note that the above doesn't quite succeed at simulating the semantics of
> the built-in while syntax. In the built-in while, __break is in scope
> for both the condExpr and bodyExpr. For both the built-in and the above
> example, __continue is in scope only for the bodyExpr.
This is easy to fix. Something like:
control myConstruct (condExpr) { bodyExpr }
==> def __break; myConstruct (&__break, condExpr) fn __continue { bodyExpr }
which is then expanded using lambda-args. The expansion of while stays as
above.
--
David Hopwood <david.nospam.hopwood at blueyonder.co.uk>
More information about the e-lang
mailing list