[E-Lang] stl-0.8.9k: Syntax Changes

Dan Bornstein danfuzz@milk.com
Sun, 21 Jan 2001 10:36:26 -0800 (PST)


Mark S. Miller writes:
>                             "_" vs "any"
>[...]
>    def _ (a :(_ < 7), _) :(_ > 3) { ... a ... }
>[...]
>    def _ (a :(any < 7), _) :(any > 3) { ... a ... }

In a bit of synchronicity, I've been working on a personal project lately
which involves a bit of language design, and I've had the need for exactly
the same distinction. In my case, the "any" equivalent will actually be
used more often than the "_" equivalent, and so I wanted to have a simple
symbol for it (similar to your motivation, the reasoning being to make it
as easy as possible to state). Originally I was going to use "_" for both
purposes, as well (in my case, the use of the two would've been
syntactically/visually less ambiguous) but eventually did decide that the
"standard" meaning of "_" wasn't quite right.

I settled on "#", which I picked because that character wasn't otherwise
used in my language, and because, most of the time, the variable it
represents will be a number. I decided to call this the "iota" particle,
since it vaguely corresponds to the iota operator in formal linguistics[*].

It looks to me like, in E, you're restricting the usage of this form to
only be usable in type restrictions, but in my case, using "#" is valid
anywhere where a variable identifier would be in an expression. The meaning
is, approximately, that "#" maximally infects the expression it is in
(without crossing statement boundaries), turning that expression into a
one-argument function. So,

    # * (# + 5)

is equivalent (in E) to

    def _ (x) :any { x * (x + 5) }

In my case, the notational terseness is a huge asset, since these expressions
will end up appearing in a 2d boxes-and-arrows dataflow form, where it's
much clearer to see something like the first form sitting next to an arrow
than the second, e.g.:

      +------------+
      | sum        |
      |            |
   -->| x: #*(#+5) |
   -->| y          |
      |            +-->
      +------------+

(This is a contrived example, but I hope it gets the point across.)

Anyway, I don't know if generalizing the form would be of particular
benefit in E, but I thought I'd at least mention the possibility. But if it
does make sense to do so, then it may make sense to differentiate this from
"any" (as Tyler sort of pointed out).

>* When "_" is used as the name in a function/object definition, then the 
>initial "define" may be left out:
>
>    def sublist := select(list, _(x) :boolean { x%%7 > 3 })
>
>* When the initial "define" is left out, if the parts after the "_" are "() 
>:any", these can be left out as well.
>[...]
>     whileLoop(_{ ...condition... },
>                    _{ ...body...})

IIRC, there was motivation to make ":none" (":void"? sorry, I forget) be
the default restriction for return type and not ":any". Is there an explicit
motivation to change the default for this case? It seems to me that it
would be more consistent and less confusing (and less likely for one to
inadvertently leak authority) to keep ":none" as the default return type.
So, your example would end up looking more like this:

     whileLoop(_() :any { <condition> }, // or :boolean
               _{ <body> })

Admittedly, this is not as clean-looking, but it restores the fact that all
return types are mentioned in some explicit way. Maybe there's another
piece of sugar that could be used to indicate "really, I want to return a
value" in a terse way. Again, stealing from my current personal project, I
have the concept of a "yield" operator, which is used to indicate the value
of a closure expression. I chose "::". Here's what it might look like:

     whileLoop(_{ :: <condition> },
               _{ <body> })

I think something like that would satisfy both constraints (easy to say and
hard to inadvertently misuse).

-dan

[*] (Glossing over a lot.) The iota operator is more-or-less the formal
    equivalent of "the" or "that". It takes a single-argument predicate
    (function returning boolean) as its argument and "returns" the one
    possible/most salient entity that could satisfy that predicate. For
    example, if "Fred" is the one "dude" in the current context of
    discourse, then

        iota (dude)  =>  Fred

    When trying to understand the utterance:

        Fred's dancing like a madman. That dude is quite talented.

    The first statement would be seen to set up a context where "Fred"
    is the most salient "dude", which is then picked up by the iota
    expression in the second statement.

    Anyway, my use of the term isn't quite the same (I use it to directly
    denote an object, not as a functor), but it does keep the sense of "the
    thing that, from context, is obviously what I mean to denote."