Block and Lambda #
This entry is a loose summary of Matz blog : 2005-06-30 , 2005-07-01 , 2005-07-21 , 2005-07-22 . And this entry is related to Ruby 2.0 block local variable and Function Call .
Matz has been thinking about new syntax of block paremter and lambda expression. As it stands, we can’t use same syntax in block parameter as in method parameter. So he has some ideas, but he is not satisfied with these ideas.
We can write block parameters like this now:hash.each { |k,v| v ||= "none"; ... }Following examples mean the same.
1. Anonymous function like Perl6
This syntax came from Perl6:for list -> x { ... }Perl6 has a near cultural sphere to Ruby, so he think it’s well to refer Perl6. But he worry whether Perl6 will be released or not and whether this syntax will be adopted in Perl6 or not.
hash.each -> (k,v="none") { ... }This syntax is so-so in block because It reminds him of a substitution. But when in lambda expression:
proc = -> (x, y) { ... }Hmmm, it doesn’t look like a function.
2. Other sign
hash.each \(k,v="none") { ... }In Haskell, back-slash sign means lambda because of form likeness. A matter is a back-slash sign displays as yen-sign by font environment. In lambda case:
proc = \(x, y) { ... }In Ruby, it look like a parenthesis escaped.
3. Double back-slash
hash.each \\(k,v="none") { ... }It’s lack of visual hint.
proc = \\(x, y) { ... }He thinks better than one back-slash case. He is worried by the same reason of font as one back-slash, too. He thinks he should lays special emphasis on lambda expression, because main dissatisfaction was an inconsistency that a syntax of lambda’s parameters is different from syntax method’s parameter in the begining.
Though he will not choice below ideas probably, I introduce.
4. New keyword
hash.each { using k,v="none"; ... }
5. Extend lambda
hash.each(&lambda(k,v="none") { ... })
He leaned toward an example like Perl6 and had done at his local repository, but he wavers yet. He wants a good idea which fulfill below condition:
- It’s able to express anonymous function.
- It puts in front of paraemters.
- It’s good mix of sign which have not been used until now.
- Many people feel comfortable (if possible).
What do you think?
murphy
I mean, we all want to write
don’t we? Is it really not possible to prefer the block-variable-| over the bit-or-| in parsing? Maybe there are other difficulties, but the only thing I see is that with this syntax you couldn’t write
so bitwise-or wouldn’t be available in block variables or something. (After the =, an expression should be allowed, including method calls, class definitions and, of course, bitwise or.)
But where’s the problem? If you really come across such a thing, just write
and the parser should be happy. You have to do this often in Ruby to make things clearer to the parser. This is also compatible to today’s syntax, doesn’t change much, and seems intuitive to me.
Maybe I don’t understand the real problem – could someone please explain? (Or translate matz’ blog for me – WHY did I learn French in school instad of Japanese??? 9_9)
Another idea, because I like keywords: extended do-end:
So weird things are only allowed in with … do … end.
murphy
Oh, I just discovered that in with…do…end, the do could become optional: You could use
with
like you usedef
:If you worry about one-liners now, just use do as you did before:
What about leaving {...} as it is, and extending do…end to with…do…end?
sporkmonger
sporkmonger
Although admittedly, the fifth wouldn’t bother me nearly as much as the previous four.
Phil
If you want to do an OR inside of the goal posts ’| |’ you need to surround it with ‘(’ and ‘)’ – I don’t see this as being a big problem. It seems to be the least disruptive approach.
If I have to pick one of the five options above, I prefer #5. However, what would that mean for anonymous code blocks? (I’m guessing it would look like the Perl6 example, but without the ’->‘).
Why is the extra arrow needed in the Perl6ish-way shown in #1? If you get rid of the arrow wouldn’t you essentially have the same thing as #5?
Tom
Totally agree with sporkmonger. I’d much prefer to have the syntax we actually want, and if it’s not possible, the current way.
JWL
1+ for keeping the current goal post syntax.
Daniel Berger
Dear murphy,
No, we don’t. Leave it alone. It doesn’t look any better or clearer to me. In fact it looks worse.
And, if your object doesn’t already have a default value, or the capability of having a default value, then you’ve probably screwed up long before you reach this point.
I’m not sure how Matz got it in his head that block parameters and method parameters should work the same. They’re different, mmkay?
Note to Ruby community: stop obsessing over blocks and procs. I don’t want the syntax wrecked over some misguided notion of block/lambda/method unification.
P.S. Hash.new(“none”)
Dan
I’m all out.
Dan
Those < and > looked great in the preview…sorry everyone. Hey _why, something to look at: < and > in the preview don’t show up, but they do when the post is committed.
Revolutionary
You are all tied up into being comfortable by avoiding change. Change is good. It keeps you on your toes to perform your best. I personally like the \() syntax.
piggie
I feel like this is trying to solve a problem that doesn’t (or barely) exist.
Both of these options look and feel like Ruby:
The rest feel (as the parent post notes their origins) like other languages entirely. The syntax of Ruby should to continue to adhere to POLS .
babie
Hi, all! Matz said that it’s too difficult to write a ”|” operator in present block because of parser(yacc).
Hi Dan. There is samples used various characters at Sasada’s diary .
matz
yep. I don’t want to introduce new syntax if we could implement optional arguments in the goal posts. I’m waiting for some super YACC guru.
hmm, “goal posts”, I like the name.
trans
Along the Perl6 line of thought this seems simpler:
method(x,y) { a,b="none" -> ... }
But the one that seems most intuitive to me is:
method(x,y) { (a,b="none") ... }
But that might have some parsing problems itself, does it? Of course one could just use backslash in place of pipes.
method(x,y) { \a,b="none"\ ... }
That should work without ambiguity. On the otherhand I find the last notation using the lambda interesting. Might we not just drop the word “lambda” and use only the & to do:
method(x,y) &(a,b="none"){ ... }
2c.
Phil
Matz: Maybe it’s because it’s not a currently available feature, but I don’t think I’ve ever needed a default-valued argument for a block. What is the problem we’re trying to solve with the proposed changes?
murphy
My knowledge of lex/yacc is very poor, but I know the problem of ambiguous symbols. A solution is, for example: Ruby scans a ”+” either as plus or as tUPLUS, depending on some lex_state.
To parse | correctly, we need a stack, because a block can contain expressions with |-op, but also more blocks that contain |-ops etc. Maybe it is enough to keep track of all opened parentheses to decide about ”|”:So it could be solved one the lexer level.
Has someone described the parsing problem in English yet? Where it lies exactly?
Another idea is maybe to use the semicolon:
But that would interfere with the new block variables section.
Mike
I’m not much of a YACC /LEX guru. But doing the nice syntax one would require infinite lookahead no? I don’t see how that could be done with YACC . Isn’t it possible to switch to a more sophisticated parser with backtracking, infinite lookahead or something like that? I think (not sure) there are some free ones that have that and are based on YACC .
The proposed syntaxes do like kind of weird… Number four seems clean to me but loses the brevity Ruby has on this right now.
Sigsegv
Here at the TU-Berlin we have opal , and they define lambdas with \\x,y. or \\_ .
Jut my 0.2 Cent
Matt
I don’t like the proposed syntaxes either. I guess adding a lot of syntax to the language for a feature that I’m not sure I’ll even use doesn’t seem like a good tradeoff that way. That way lies madness. And perl.
sporkmonger
phil: I know, I was wondering that myself. To be honest, even if the current syntax were maintained, I can’t think of any good reason I would want or need to use optional parameters in a block. So I have to ask, is the point of all of this just to blur the line between blocks and methods for the sake of it, or do we have some more practical purpose for all of this?
trans
I just noticed something else that’s nice about this notation:
method(x,y) &(a,b="none"){ ... }
It slips right into the parameter list:
method(x,y,&(a,b="none"){ ... })
That’s a plus.
trans
On the otherhand, why not deprecate the | operator in favor of ^? Double-bar || could remain b/c it would be unambigious.
Moe
And deprecate
^
in favor of what then?jvoorhis
If anyone actually reads this far down, I advocate the conservative approach of leaving well enough alone unless we get
|k,v='none'|
.I’d rather write
v ||= 'none'
on the next line and keep my backwards compatibility than rewrite my existing code so I can have a different syntax for functionality that I rarely use (or have seen others use for that matter).Wouldn’t you like to be able to use Ruby 2.0 right away? :)
cmo
Here is a syntax which is a mix between substitution syntax and the one in point 5:
list.each((x,y)->{...}) and proc = ((x,y)->{...})
’# Can double parns signify a block or/and lambda without parsing problems?
hgs
There is information in the FAQ about weird results with
puts
caused by the parser which baffles new users. We now have this. There have been other issues (I forget what) which have been constrained by the parser. I would suggest that serious thought should be given to re-working the parser before re-working the syntax. YACC is fairly old technology now, there are GLR parsers, and probably other things I am unaware of. [Disclaimer, my ability to write parsers has proved particularly weak, so I claim no expertise]. Surely There’s A Better Way To Do It, isn’t there?vontrapp
For what it’s worth, I like the current syntax because it’s clear where those variables go. They are inside the block, which makes sense to me. If we really have to change it. I guess I would prever the
(x,y)->{...}
because it gives the notion of x and y injecting into the block.(x,y){...}
in all it’s forms just doesn’t flow to me, it’s a lot more effort for me to parse it. Does anyone else feel the same?Dave
I like murphy’s with…do…end idea, but I think I’m the only one. Of all the options, it’s the only one that makes the sense at-a-glance about what’s going on.
Then again, I never really liked the goal posts – they always strike me as a quirky hack.
trans
Well, given how rare it is,
#xor
would probably do, but never fear^^
is here.(P.S. Ironically I was looking a MathWorld site and ^ is more akin to symbol used for AND . Go figure!)
Nyarly
For what it’s worth, I agree with you, Dave. I like with (arg=0) do … end.
Especially because it can be used in semantic analogy to def. I am a little curious about how it would work in terms of zero argument blocks. looks a little weird.On the other hand, I’ve come to love the goal posts as a quirk of Ruby. I suspect that, the same way that, by convention, one line procs are {} and multi lines are do…end, mutlilines will become with () end, and oneliners will become {|| }.
MenTaLguY
with … do is my favorite next to goalposts. I imagine with zero-argument blocks you’d omit the with. No arguments to do it with after all.
with … do really is the best of the alternatives; I hope matz is following the thread…
Sam
The haskell lambda example given is for a uncurried (tupled) anonymous function. It is not required that the anonymous function be written that way.
\x y → x + y
which is just shorthand for
\x → \y → x + y
caleb
It didn’t take me too long to extend RubyLexer to get default parameters in blocks working the in murphy’s preferred way. I don’t really speak yacc, and the algorithm isn’t a simple one to implement by itself, since the right-hand-side of the default parameter needs to be able to be (almost) any ruby expression.
caleb
Matz, what are the chances of using RubyLexer in the ruby interpreter? ;)
ko1
some examples are here: http://pub.cozmixng.org/~the-rwiki/rw-cgi.rb?cmd=view;name=Ruby2.0BlockParameterNotation
maldoror
I like the pascaliness in with … do but that’s just the little Wirth in me
flori
I really like Trans’ first example:
f = { x, y → x + 2 * y }
f[1, 2] # => 5
g = { → :constant }
g[] # => :constant
h = { → }
h[] # => nil
It looks almost like the mathematical way to define functions. It should be easy to parse this with YACC , or do I miss something?
William
I too see limited usage of default variables in block arguments, but if we MUST have them, I agree with Murphy: rewrite the parser until something like
hash.each { |k, v = (k|0)| ... }
is possible.
All of the proposed syntax changes are ugly and involve too much typing for something that SHOULD be as simple as possible. Ruby has got this right and no other language does—let’s not break that now.
Sam
Can we have our lambdas with curry… please???
Brian
What stands in the way of
which is nicely similar to
withPS: I’m, sure I missed something
JasonWatkins
I like murphy’s suggestions as well, including the with keyword. I don’t think I’ve done enough ruby to know how useful default params in blocks would be… but it seems like a reasonable compramise to keep the goalposts as is, and force those who need defaults to use the with form.
I don’t like the way any of the 5 proposals look. Assuming it’s a rarely used syntax, like the generally delimited input, I don’t see how it would hurt anything to use the double slash though.
Jeff
I like the with [do] end syntax … but I think this would be a good place for list comprehensions like python
why not just turn #each into
or
then they add some cool optional conditionals … very cool stuff.
Jo
@Matz: A YACC alternative is www.antlr.org & xpa.sf.net. BTW , the best compiler technology available is OCAML ; see www.ocaml-tutorial.org and for an example mtasc.org. The Perl 6 VM is based on Haskell, cf. www.pugscode.org.
wolverian
@Jo: Pugs is “only” a bootstrap compiler for Perl 6. The final compiler will be written in either Perl 6 or a subset of it aimed specifically at compiler production. That’s the plan, anyway.
What does that have to do with OCaml, anyway? :)
I’ve always hated the goalposts in Ruby, in addition to the complete lack of English similarity.
That simply does not read naturally to an English reader (which I’m not, incidentally, but close enough to feel the syntax odd.)
That’s my preferred syntax, but it really is rather unrubyish, I guess. But then again, I don’t like the Ruby idiom of .each in the first place.
I prefer
list -> elem
overelem in list
because I consider the list to be more important than the iterator element.Jo
@wolverian: Pugs 6.2.8 ff. is intended to become a full-fledged Perl6 compiler. I’ve even read that Pugs might one day even be capable of producing Perl6 code. – Haskell is a very good compiler language . . . and so is www.ocaml.org. Would be cool to know if Autrijus also took a deeper look into the alternative!
wolverian
@Jo: Yes, but it’s not meant to become the reference implementation. Sorry, this is OT discussion, really. :)
sam12
For those interested in more information on Perl6 issues & discussions see: www.sidhe.org/~dan/blog/ (Dan Sugalski, developer of Parrot) and the Periodic Table of the Perl6 Operators over at www.ozonehouse.com/mark/blog/. To compare code in terms of readability you also might want to ckeck out such sites as pleac.sf.not or www.talkaboutprogramming.com. In Perl5, e.g., you have the foreach-loop pattern that first names the iterator and then the list: foreach $variable (@array) ...
wolverian
@sam12: Dan Sugalski is not a Parrot (lead or otherwise) developer anymore, he gave off the hat to Chip Salzenberg. He was never a Perl6 developer, although certainly Parrot and Perl6 are related.
murphy
But what about the block problem?
Pieter
I dunno – while my experience with Ruby is very (very!) limited, and while the “goalpost” notation still feels wierd, both of murphy’s suggestions seem to feel consistant. Personally, I like the verbosity of with..[do]..end, but I can see the reason in the “extended goalpost” notation. The other options just felt wrong. That’s all I can say.
murphy
Maybe it’s better to talk here: comp.lang.ruby
By the way, the whole thing is just for lambdas; matz won’t change normal block syntax.
sam12
An improved parser may do the trick: allow more code syntax options, protect against ambiguities, ... (see above). However, I’m wondering if a preprocessor could do the trick as well (cf. man perlfilter; for a Ruby preprocessor example see rubystuff.org). @wolverian: perl6.concat(parrot); parrot.concat(perl6), ... or just understand Perl6 as an umbrella word for both Perl6- and Parrot-related issues!
wolverian
@sam12: You mean “perl6” ~ “parrot”, right? ;) Anyway, thanks for the clarification. Being involved in the process makes me differentiate between these things more than the someone outside, I guess.
Jo
A full C parser written in OCaml that modifies the lexer while parsing is the C Intermediate Language (manju.cs.berkeley.edu/cil/). Would be cool to have such a thing for Ruby as well (in addition see rockit.sf.net and merd.sf.net for Ruby; and the OCaml preprocessor by martin.jambom.free.fr/ocaml.html).
tz
Jo, you’ve overlooked this one: nekovm.org
Comments are closed for this entry.