I've just been forced to learn about a new language proposal, a new (to me) set of morphisms, and a nonstandard approach to proving stuff in topology. That's a rich link.
I think Haskell is overall terser than Ruby. The trouble with the accgen test is that it's imperative, and Haskell isn't meant to be. Here's the Haskell implementation that I would submit:
In ML you can get a similar terseness to that of Haskell, but with support for imperative programming. If we allow the increment function to be predefined (as the Arc example does):
The original ruby definition is 15 tokens, the .to_proc version is 13 tokens.
Orthogonality:
to_proc
3 variables (foo, n, x)
1 method call (to_proc)
1 type of separator (')
2 assignment ops (=, +=)
2 binary operators (->, .)
9 different kinds of tokens, in 5 (arbitrary) categories.
Original:
3 keywords (def, lambda, end)
3 variables (foo, n, i)
5 Separators (|, {, }, (, ))
1 assignment (+=)
12 different kinds of tokens, in 4 categories.
So the only way the original ruby version comes out ahead by these measures is that it has "fewer categories" of token types that are required. Also I think that with the 'def foo' declaration, 'foo' is not technically a variable. I don't really know ruby well enough. But you get the idea.
Well, by definition it's more readable, since nobody is familiar with the new notation yet. But objectively it has problems: unnecessary def and lambda keywords, using () and || for argument lists, using def .. end and {} for scopes. There's room for improvement.
Personally, I like many things from Haskell's syntax. I wish I could say this in Ruby:
That holds true for the given ruby implementation as well, since n is incremented only in the scope of foo and not in the calling scope.
def foo (n)
lambda {|i| n += i }
end
n=5
a = foo(n)
puts a.call(3) #prints 8
puts n # still prints 5. n is not incremented
I agree that the python one is strictly not according to the problem definition, but for all practical purposes both python equivalents are the same, aren't they? or am I missing something?
I tend to agree with you. It's obvious to me that the following code evaluates to 6:
r = 2
foo = lambda {|x| x * r}
foo.call(3)
And it's obvious to me that the following code raises an ArgumentError:
foo = lambda {|x,r| x * r}
foo.call(3)
But what does this do?
r = 2
bar = 'x*r'.to_proc
bar(3)
Do I get the 6, or do I get the ArgumentError?
UPDATE: I presume the answer is "ArgumentError" (because the alternative appears to be positively evil), and that what I really need to do is this:
r = 2
bar = 'x -> x*r'.to_proc
bar(3)
Why is this such an improvement over lambda? Couldn't these folks just fix lambda (e.g. to remove the need for that annoying .call method every time I use the result) rather than deciding that every Ruby programmer needs to learn yet another argument syntax?
There are at least two kinds of folks: those who are "fixing" Ruby the language, such as the Rubinius team, and those who are "using" the language.
I am in the latter camp. So sometimes I complain about what is broken--http://weblog.raganwald.com/2007/02/why-ruby-is-not-acceptab... sometimes I hack around it. But no, I am in no position to change the language. If I was, I would actually implement the point-free and underscore conventions natively.
If you want to use closures, you want to use lambda, not String#to_proc. If you dislike using .call, Ruby also allows [] syntax, so:
But please don't spend too much time explaining what I'm doing wrong, because I'm afraid I don't like foo.[3] anyway. :)
Let me demonstrate my problem by taking a simulated tour through my brain as it encounters foo.[3] for the first time:
"WTF?
"Did someone mistype foo[3]?
"No, wait, surely it's supposed to be foo(3). I'm pretty sure that foo is a function. Didn't we set it equal to a lambda expression three lines ago?
"Maybe I need glasses. Let's adjust my monitor. No, those are square brackets, all right. And that really is a period between "foo" and the brackets.
"Maybe Google can help. But I'm not sure how to google '.[]'
"Oh, no -- is this one of those mysterious edge cases of the Ruby syntax? Do I hear _Why laughing at me? Does foo.[] magically target the eigenclass, or the metaclass, or the zetaclass, or something? Or did one of the libraries secretly redefine the core language behind my back?
"omigod, I should have learned Python.
"No, wait! The dot means that we're calling a method. And I know that [] is a method -- we redefine it all the time. So foo.[3] is just an obscure-ass way of calling foo[3] .
"Which makes no sense, because I thought foo was a function. So I must be wrong.
"WTF?"
[ten minutes later]
"Aargh! I went through ten minutes of confusion just to save three characters?"
I may have exaggerated this a little. And, yet, I really did have no idea that .[] works, and I still have no idea how it works. (Of course, in my version of Ruby, it apparently doesn't work, which makes it hard to investigate.)
Now, don't get me wrong -- Ruby is my favorite programming language. Quite often, after the tortured syntax, the monkey-patched class, or the strange new DSL stops you dead in your tracks, you'll struggle through the learning curve and discover that you have a powerful new technique. This starts on day zero of Ruby, when you see your first block. It looks like nothing on Earth, but it turns out to be insanely great.
Symbol#to_proc is a borderline case. I like the idea, but I hate the syntax. The &: doesn't bother me as much as the lack of curly brackets. To me, idiomatic Ruby is about blocks -- I expect map() and inject() and delete_if() to take blocks, not arguments. I would really prefer this:
my_array.map {_.get_funky}
Reading this makes me happy. There's a map() call, so I expect a block, and look -- there are the curly brackets. And because it's a block, the stuff inside it must be a method call. And, in fact, the underscore and the dot mean that we're invoking a method on a placeholder. All is well with the world, and no higher brain functions need to be engaged.
But, you know, life isn't perfect. Language is about communication, and ultimately the language you speak is determined by what other people are speaking. Symbol#to_proc is powerful enough to become popular, and popular enough to be idiomatic, so we all have to learn it. Perhaps I'll even start using it.
But I'm afraid String#to_proc, like foo.[x], is past the point of diminishing returns. Do I really need a version of lambda that is not only utterly unlike Ruby's usual lambda, but is even less like Scheme's lambda? And are my colleagues really going to forgive me for asking them to learn Haskell syntax in order to read something as trivial as lambda {|x,y| x+y} ? I'm not even sure if I could forgive myself!
Hey, neither can I. Quite possibly because foo.[3] actually doesn't work, it's foo[3] that works and I made a typo.
Sorry about that, and especially too bad considering how your first reaction was to consider the possibility that your version of Ruby was at fault instead of the possibility that I made a careless error. I appreciate the implied vote of confidence, but I'm aghast at the consequences.
I appreciate your taking the time to share your reaction. I'm mulling over exactly what I prefer about the point-free syntax, and the prod to think thinks over may help me understand my own views in more depth.
So, part of me is tempted to use this as an example of the reason why languages benefit from a certain amount of redundancy and consistency. :)
The other part of me is quite embarrassed, because I thought I had tried foo[3] and failed. I guess that's why everyone in the Ruby community prefers automated testing!
Of course, if I thought that applying an array reference to a Proc made any sort of intuitive sense, I might have tried it more carefully. :) I still wish that I could just say foo(x).
Anyway, I'm glad you appreciated my report from the field. And of course you prefer the point-free syntax -- you know Haskell, you know Lisp, you seem to know a certain amount of mathematics. It all makes perfect sense to you, just as I can only dimly remember the time when vector calculus didn't make perfect sense to me.
But I shouldn't indulge my love for German by randomly German syntax into my English prose inserting. Unless I have a very good reason: perhaps I want to borrow the uniquely compact German word shadenfreude, or perhaps essential it is the alien character of Yoda to establish. When you break the rules in Ruby code that you intend to show to someone else (and is there really any other kind of code?) you need to convince the reader that you had a very good reason, because you're making him or her work harder to understand you.
Keep playing with the syntax for a while. You may find that it's so elegant that it is worth defending against the inevitable skeptics. And, if not, at least golf is a very pleasant way to pass the time!
I study math, hack Scheme, and find myself totally confused by terminology.
Maybe it's a riddle or something -- "What does complex-smoothness have to do with lambda calculus?"