Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Matz might say that, but doing functional things in Ruby is a pain in the arse as well. Blocks, Lambdas, Procs, and Methods, all which are slightly different and require transformative functions to move one into the other. That's about as far from an s-expression as you can get.

That being said, having the easy ability to create lambdas or blocks is hugely benefitial. sighs and I wish python would hop on board there, but I don't think it ever will.




Yeah... sobs it's a nice band-aid, but an inelegant solution. I would much rather that they all just be Proc or all some other mythical procedure class of the future. I figure that would break the whole ruby method call chain, though I don't see any reason why blocks couldn't just become straight syntactic sugar for lambda (I would love that)


A little off-topic, and I apologise to everyone for our exercise in bikeshedding, but... :-)

The problem is that Ruby blocks were designed to imitate the behaviour of C-like blocks, while lambdas are true closures. (Don't get me started on why procs are just like lambdas only different).

The difference between a block and a lambda is most clearly seen by asking what the return keyword does in a block vs. what it does in a lambda.

So in Ruby you can write something like:

    def which_answer_is_correct(*answers)
      answers.each_with_index do |answer, index|
        return index + 1 if answer.to_s == '42'
      end
      return 'none of the above'
    end

    which_answer_is_correct('black','white',42,:symbolic_logic)
      => 3
If blocks were syntactic sugar for lambdas, this method would always return 'none of the above'. Of course, there is another, very elegant way to write this method that doesn't rely on the return keyword or the semantics of blocks, and one can easily argue that this would be an improvement.


(though my intention was not to derail the conversation. This is a niggling difference between ruby and python that irks me :-D)

Right I would be arguing as the latter.

My problem is that these small niggling differences between all the different types of callable items (including what I think is simply disgusting use of a special form "yield") confuses the whole mess.

I'm glad that all these different ways to use callables exists. That's "A good thing" in my opinion. But I can't help but feel that their quirks and differences couldn't be consolidated into a single experience.


derail the conversation

De-rails-ing conversations about Ruby is often an improvement.


Good sir I do say... that was quite the pun :-D

takes his hat off


Doesn't Ruby have call/cc?

  (def which-answer-is-correct answers
    (let like-ruby-block 
       (fn (answer index return) (when (is string.answer "42") (return:+ index 1)))
       (ccc [do1 "none of the above"
                 (on a answers (like-ruby-block a index _))])))
as a useful contribution to the topic: Python does not have a call/cc

and how would the return statement be scoped if the block was created inside a different function?


Yet more bikeshedding, this time in Lua!

This first approach doesn't use an internal lambda but is idiomatic - (do/end does not create a block in Lua - it creates a scope):

At the Lua repl:

  > function which_answer_is_correct (...)
  >> for index, answer in ipairs {...} do
  >>   if tostring(answer) == '42' then return index end
  >> end
  >> return 'none of the above'
  >> end
  > =which_answer_is_correct('black', 'white', 42, 'symbolic_logic')
  3
The next approach duplicates the semantics of the Ruby code you posted, if Ruby blocks were actually lambdas:

  > -- first a bit of magic to make Tables act more like in Ruby
  > mt = { __index = table }
  > function Table (t)
  >>     return setmetatable(t or {}, mt)
  >> end
  > 
  > function table:each_with_index (block)
  >>     for index, value in ipairs(self) do
  >>         block(value, index)
  >>     end
  >> end

  > -- now actually write our function:
  > function which_answer_is_correct (...)
  >>     local answers = Table {...}
  >>     answers:each_with_index (function (answer, index)
  >>         if tostring(answer) == '42' then return index end
  >>     end)
  >>     return 'none of the above'
  >> end
  >
  > =which_answer_is_correct('black', 'white', 42, 'symbolic_logic')
  none of the above
Now, if you want the nonlocal return properties of Ruby blocks in Lua, you need to be a bit more clever than I feel at the moment. There's probably a trick available via coroutines, because coroutine.yield() yields to the caller of the currently running coroutine, rather than to the caller of the currently running function.

Making anonymous function creation less verbose is a popular topic on the Lua mailing list. "function (args) return args end" is more verbose than "do |args| args end". There are several implementations via community-developed macro extensions. I wouldn't be surprised to see something appear in the Lua 5.2 RC candidate later this year.

In the real world, I'd probably write something like this in Lua:

  function which_answer_is_correct (...)
      return table.find({...}, function (value) return tostring(value) == 42 end)
  end
Implementation of table:find(cond) is left as an exercise for the reader.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: