Re: Extending define with 'where clause




Alan Grover wrote

> Note that your name, define*, collides with guile's define*, which is
> parallel to lambda*, which implements automatic handling of keyword
> arguments. I'd rather see the name not have a '*', as that seems to suggest
> a parallel to the 'let' forms.

I am aware that there are more than just one name collision for a
stared define across different existing implementations and proposals.
For example, Andrew Wilcox proposed "define* macro: a solution for
sequential definitions within syntax-case expander modules" in his
message to this list on Dec. 7, 2004. {See also his follow up in a
separate thread).
Chapter 27 of "PLT MzLib: Libraries Manual", "package.ss:
Local-Definition Scope Control" introduces -- among other forms -- the
define* form, which is being described as: "Like define, etc., but when
used in a package, they define identifiers that are visible only to
later definitions and expressions."

I introduced the name define* just as a working name. As long as I am
the only user of such facility it really does not matter how it is
called. But if there is more interest in using such macro I will leave
it to Scheme experts to decide on an acceptable name.

I was hoping to be able to rename it as the "define" instead. The
reason is that the "define*" is exactly equivalent to the "define" --
as long as the "where" keyword is not used. In other words, one could
append the star to any "define" in any existing standard Scheme code --
without changing the semantics of such code. It is only when the
"where" clause is used that the new syntax really matters.

>>From this perspective, the proposed "define*" is a syntactic extension
to the existing "define", and hence the name "define+" (indicating a
syntax extension rather then a syntax replacement) would possibly be a
better name for it -- if there is no easy portable way to rename it as
the standard "define".


> Can I suggest an introduction?
[... skipped]

Your introduction is fine. I did not elaborate on this because I did
not want to sound like a troll -- being a newcomer to this list and
complaining about the time proven syntax that everybody else loves. But
my motivation was strictly practical and was not meant to criticize the
standard syntax. Truthfully, I often have problem understanding complex
examples I read on net until I re-write them into the "where clause"
forms. Maybe it is just me, but some huge pyramids of a code --
introduced with the help of let, letrec, letrec*, or named let -- are
quite often incomprehensible to me from the first glance. On the
contrary, the "where" syntax promotes (1) the top down approach:
generalities first, details later and (2) much clear code structure.
Heck, you often can save on few pairs of parentheses too (when
replacing let or letrec). :-)

You may not be aware of the fact that the "where clauses" can be used
in any level of complexity of a function definition. This is because
the macro is recursively defined -- with stars appearing on the
transformer sides. As a result, you can construct something like this:
(define* (f x)
(....)
where
(define* (g u)
(....)
where
(define c 10))
(define (b x)
(...)))
Here, the variable "c" is only visible in the scope of function "g",
while function "b" is visible in its parent "f" and its sibling "g". As
I said before -- any "define" form used here could be replaced by a
"define*" form.

Finally, because of its clear syntax, the "define*" helps to reduce the
topmost namespace pollution: the definitions that are really local to
some main function can be added to that function as the "where"
clauses. This helps in organizing and understanding the code structure.
I have run such transformations on several major examples of existing
code: meta-circular interpreters, unification routines, type checkers,
pattern matchers, etc. and I am pleased to report that the transformed
code looks neater and is easier to comprehend. At least for me... I
should add that in Haskell/Clean communities both "let" and "where"
forms 2are used on par: some prefer the former style, some -- the
letter.



> Could you specify the semantics?
I have strictly followed the R5RS, section 5.2, Definitions. Notice
that the Standard mentions the three forms for define.
(define <variable> <expression>)
(define (<variable> <formals>) <body>)
(define (<variable> . <formal>) <body>)

I have added a form with the explicit "lambda" in the body of a
definition in order to handle it correctly when the "where" clause is
added later. For each of those standard forms I introduce one dummy
rule that does nothing else but rewrites "define*" as "define" and
another that adds "where" clause to the definition. (More or less.)

The rules with "where" clause do nothing else but implement subsection
5.2.2, Internal Definitions:
"Definitions may occur at the beginning of a <body> (that is, the body
of a lambda, let, let*, letrec, let-syntax, or letrec-syntax expression
or that of a definition of an appropriate form). Such definitions are
known as internal definitions as opposed to the top level definitions
described above. The variable defined by an internal definition is
local to the <body>. That is, <variable> is bound rather than assigned,
and the region of the binding is the entire <body>."

> I'd be interested in an implementation that respected lexical order in the
> siblings, more like let*. So, rather than the 'where' bindings being scoped
> any-where, they'd be scoped in the body, and in _later_ siblings.
> ...
This is certainly possible. I deliberately kept everything as simple as
possible for the first discussion -- if any.


> Instead of 'compute', would 'begin*' make sense?
It would. I originally named it "get", but since "get" implies some
result I finally choose something suggesting evaluation. Besides I am
tired of "get" in Java. :-) I do not use it as often as define* (aside
from some top-level evaluation), but there are cases where (your)
"begin*" is useful in simplifying some code in some complex "define*".

.



Relevant Pages

  • Re: CROSS JOIN
    ... > was that depreciating the original FROM .. ... WHERE syntax would never ... > The problem is that the WHERE clause is done after the FROM clause. ... but thats just outer join stuff. ...
    (comp.databases)
  • Re: Not Exists joining 2 tables
    ... "'code' is a bad name for a key column" is a valid complaint. ... EXISTS clause with a correlated subquery properly, ... SQL+ syntax and start using the ANSI SQL syntax that seems ... Then the only criteria in the where clause ...
    (comp.databases.ms-sqlserver)
  • Re: update query: still having problems
    ... Only the records from Department that have a rate value present in sheet1, ... That is how an INNER JOIN works when there is no duplicated values (in one ... you add an extra WHERE clause. ... Your code throws up a syntax error: ...
    (microsoft.public.access.queries)
  • Re: Method annotation and anonymous functions
    ... anonymous functions and anonymous closures (so def and lambda could have ... the same syntax but lambda would create a closure, ... class Foo ...
    (comp.lang.ruby)
  • Re: define-syntax how-to question
    ... lambda list for the final lambda form. ... much more difficult to deal with the wrapped syntax objects that you ... r5rs and define-syntax, ... let extensions provide their own define-xyz-method macros. ...
    (comp.lang.scheme)