Michael Lazzaro wrote:

>  On Monday, January 20, 2003, at 12:30  PM, Smylers wrote:
> 
> > It was only on reading that (and discovering that you hadn't
> > previously known about the 'optional comma with closure argument'
> > rule) that I understood why you had previously been so in favour of
> > proposed new syntaxes: through a desire to banish the Perl 5 syntax.
>  
> Yes.  Again, it's not that I never knew about the perl5 rule,

Sorry, I wasn't meaning to suggest that you didn't know Perl 5; I was
specifically referring to your saying that you'd presumed that
conditions and loops were special cases in the grammar, but that
actually they'll be dealt with by the general Perl _6_ rule about commas
and closure arguments.

> it's that I _dislike_ the perl5 rule, ...

Oh.  That's "dislike" rather than "disliked"?  My question was
predicated on your declaration "I emphatically withdraw my objection",
which I took to mean that your knowledge of the infrared comma rule --
or whatever it's called -- meant you no longer disliked the Perl 5
syntax?

> as I dislike most special-case grammar rules.

So do I!  I was particularly impressed by the ultraviolet comma rule,
and how it avoids special cases, when Damian paraded it at a talk last
summer.

I also don't reckon it's _that_ special.  So long as the rule is that
such commas are optional, as distinct from their absence being
mandatory, then the rule is a very general one: commas may be omitted
where they aren't needed to delimit list items.  Obviously with string
and numeric values commas are always required:

  $a -1

They are the only way of determining op/term for the minus sign: a
single argument of one less than the value in C<$a>, or two arguments
with the second being minus one?

But closures can be unambiguously determined without commas.  Since
whitespace is no longer allowed in hash look-ups, space followed by an
open brace must be the start of a closure, and hence another argument.
Similarly once the closing brace has been reached the closure is ...
ahem, closed, so anything following must be a separate argument.

> If we dropped C<map>, etc., we could drop the inferred-comma rule as
> well (unless we're really successful in making C<if> a simple
> function, in which case we need the rule anyway, so who cares?)

I guess that's the crucial issue.  Since it was Damian saying that it is
possible to have C<if> and friends as functions -- and since this was
something that'd already been dealt with before I joined this list, and
so presumably would've had any impossibility pointed out -- I believed
it to be true.

There's another sub-thread casting doubt on -- and trying to resolve --
the issue.  I completely agree that whether the infrared comma rule is
needed over there makes a big difference to its use here.

But I think I disagree about the "who cares" part ...

> But the inferred-comma rule is tangential to my dislike of the current
> C<map> syntax.  I'd dislike C<map>, and like pipelines, even if the
> inferred-comma rule wasn't there.

As you've not doubt noticed, I'm the opposite: I like C<map> and don't
(yet?) see the point of right-left pipelines.  (That means not that I
claim you're in some way 'wrong' to have those preferences, merely that
we think differently to each other.)  There's one Perl slogan that'd
suggest having both ways in the language, so both of us get to code in
the way we like.

Countering that is the risk of adding too many ways of doing things and
just causing confusion for everybody with all the different ways of
invoking functions/methods on data.  Hence my quibble with "who cares":
I could probably be persuaded that it's 'better' for the language not to
have the Perl 5 syntax, my preference, than to have so many alternative
syntaxes.  (I'm not sure.)

> > Mike ... do you still find right-left pipelines as compelling as
> > you've previously argued?
> 
> Yes, very much so.  ... I've seen quite a few newbies struggle with
> the C<map> syntax;

Me too.  The most-strugglable bit for many has been the right-left data
flow, that you start by typing where you want the data to end up, then
the process it goes through last, then the process it goes through
first, and lastly the data that's being processed.  Left-right pipelines
should be great at fixing this.

> the most frequent mistake is to reverse the order of the arguments,
> saying
> 
>     map @a, {...}

That happens if you conceptualize C<map> as taking two arguments.  In my
mind C<map> operates on items in a list (and it just so happens that
in Perl an array provides a list):

  map { ... } $a, $b, $c;

So C<map> takes _many_ arguments, and one of these arguments is not like
the others.  And it makes sense to put the 'special' argument first.
(That's also how I remember which way round things like C<join> are.)

Thinking of it as operating on a list of things also helps to emphasize
that C<map> processes just a single item at a time, that it isn't an
agregate operation on the items as a group.

> (Another common one is to not understand what C<map {...} @a, @b>
> would do.)

That's easily dealt with once somebody's got the idea that map processes
lists -- and that Perl flattens lists, something that I admit isn't
intuitive but is fundamental, useful, and applies to so many places in
Perl that failing to grasp it leads to difficulties in many more areas
than just with C<map>.

> There's a couple of reasons for that, IMO, but the wording I often get
> when I'm trying to get people to verbalize "what this statement does"
> is that "it takes @a, and does <blah> to it".
> 
> In other words, when newcomers verbalize the statement, they tend to
> think of the C<map> as operating on @a.  Which is true.  You might
> also say "it does <blah> to @a", which is also true.

Kind-of.  I go for "it does blah to each item in the list,
individually".  I want to think about a single item in isolation (then
extrapolate that once my code works for that item, it'll work for the
rest of them).

> The simple fix would seem to be to emphasis the "it operates on @a"
> part, so that people more easily remember it from the way they
> verbalize it.

My trouble with that is that it's emphasizing an array, and I reckon
it's thinking about arrays that's causing the confusion!  Also, this
still needs to work on arbitrary lists.  I know that an implicit array
ref can be assumed, but then the OO syntax leads to emphasizing
something that isn't even there.

> Obviously, an OO style fixes that easily:
> 
>     @a.map {...};

Putting the 'special' argument first means that it can be seen.  The
Perl 5 syntax means that the code and the beginning of the list are
easily seen together; the end of the list may've scrolled off the
screen, but the unseen items are probably going to be similar to the
ones you can see.  Putting the list first means having to read through
all the items before finding out what on earth is happening to any of
them.

> That's very intuitive to people, esp. new converts from other
> languages.

I'll grant that many converts are likely to find it intuitive, but I
don't find it intuitive, especially when applied to lists.  Converts
from those 'other' languages are unlikely to be familiar with the power
of throwing arbitrary lists around the place, so are unlikely to state a
preference for a syntax that permits doing so.  (Indeed people with
strong OO backgrounds are likely to prefer an OO syntax for everything,
but that isn't sufficient reason to make all of Perl OO!)

> And, happily, it's very easy to implement and extend.  But it works
> only in one direction, L2R.  (And, as Damian stated, chaining:
> 
>     @a.map {...} .sort {...};
> 
> probably wouldn't work at all, unless you tossed some parens around
> all your curlies.  Yuck.)

Thanks; I'd missed that and had the mistaken impression that chaining
was possible.  Being corrected makes me dislike this syntax even more.
Having some limits in a language so as to keep backwards compatibility
is irritating but understandable; specifically adding in a _new_ syntax
for operating on list items that doesn't permit chaining (piping,
sticking the output of one op into the next, whatever) seems a little
odd.

It may help some language converts initially, but they are going to have
to learn a completely different syntax to do more general things with
C<map> and friends.  That's more things to learn in total (and means
that while they are on the 'conversion' syntax they are baffled on
seeing others' code with other syntaxes -- much more so than if they'd
initially learnt a more flexible syntax).

> So fine, we convert C<map>, etc., to be methods of collections, as is
> typical programming practice these days.

I don't want Perl to be a _typical_ language!!  I want it to be a really
good language!!

> And, in fact, we _are_ doing that elsewhere in the language.  Things
> like C<length @a> will become C<@a.length> or similar.

But length is a property of an array as a whole, not of its elements
treated individually.  The OO syntax definitely makes sense here, but it
doesn't follow that it's great everywhere.

> But in doing that, we lose a lot of functionality -- mainly, the
> simple L2R and R2L chaining that we have now.

Yup.

> So people want to keep C<map> as functions, not methods, and use the
> old syntax.  Well, that's OK, but we're back to the beginning.

Some of us don't mind the beginning!

> Here's where the pipeline suggestions come in.
> 
>     @out = map {...} <- @a;
> 
> Here's the important part:  This same syntax will work on ANY object, 
> and ANY method of that object.  So you're removing the specific global 
> functions C<map>, C<grep>, C<sort>, etc., and replacing them with a 
> generic syntax for right-to-left chaining for any operations object.  
> You don't have to _build_ functions that can support chaining, because 
> _any_ method can be chained.

But at the moment any function/method can be chained simply by returning
something which is accepted as input to another one.

> And it provides a very visual way to define any pipe-like algorithm, in 
> either direction:
> 
>     $in -> lex -> parse -> codify -> optimize -> $out;   # L2R
> 
>     $out <- optimize <- codify <- parse <- lex <- $in;   # R2L
> 
> It's clear, from looking at either of those, that they represent data
> pipes.

Yes; that is nice.  I'm just not convinced that it's sufficiently nice
to require adding yet another way of passing data around to the
language.  I'm happy enough with the asymmetry that occurs just having
the arrows to indicate 'reverse flow' data.

> Whether you would code a pipeline as L2R or R2L depends on the specific 
> algorithm you're representing, and is purely a matter of taste...  
> you'd probably use R2L in the same places as you use C<map>-like 
> chaining in Perl5.  I can't begin to justify why one should be superior 
> to the other, and would certainly use them both.

I completely agree with all of that.

> So that's what it gains you.  The ability to visually express pipe-like 
> algorithms, in either direction, using OO techniques, without a lot of 
> parens, without relying on global functions, and with only a couple of 
> extra chars.  That's why I'm gung-ho on it.  Even if it's named <~ or 
> <|.

Thank you.  I've read everything you've written.  I understand what
you're saying, and why you like this syntax.  But I'm still doubtful of
the benefit.  Maybe I'm just too sceptical about OO in general and so --
even though I use OO in Perl -- tend not to think in those terms?

> <Fine, but really -- why kill the old C<map> function?>
> 
> Well, if we have both OO C<@a.map> and OO-based pipelines
> (post-invocants and, um, pre-invocants?), then we don't need the old
> C<map>.  It's redundant.

Fair enough.  I'm certainly agreed that at least one of those syntaxes
is redundant!

> To most people here, C<map> is ingrained.  You learned it, now you
> know it.

That's a fair point.  Most people have a natural tendency to resist
change, and I'm not sure how selfish I'm being about this.  People on
the Perl 6 list are likely to be biased towards Perl 5 ways of doing
things.  (Or:  For every feature in Perl 5 that somebody wants to
change, there's bound to be somebody else on this list who likes it just
the way it is.)

> Newbies don't,

I liked C<map> very much as soon as I saw what it did.  That, and the
way Perl makes light work in general of processing arbitrary lists, is
something I really like about Perl.  And I want Perl 6 still to be
Perl-ish.  Some other people currently prefer other languages.  Some of
those people may like to move to Perl 6.  Some of them may still prefer
other languages.

That's OK; if somebody's happy with the language he/she's using, then
let them continue to happily use it.  We should take inspiration from
other languages so as to improve Perl -- but that's not the same as
bolting bits of other languages into Perl in an attempt to bait Happy
Other-Language Users and trick them into using Perl.

> but even newbies seem to understand that C<map> or C<grep> is an
> operation on an array -- they just can't always remember the Perl5 way
> of phrasing that.

That, of course, is taking the narrow viewpoint that they are ops on
arrays ...

> Was that an understandable explanation?  :-)

Yes.  Thanks, again.  Please don't take personally my disagreeing with
so much you've written!

Smylers

Reply via email to