Forum: Ruby Underscore

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
827b1643b9e1ac6af6a9341db5bd3f6a?d=identicon&s=25 Jon Harrop (Guest)
on 2007-05-29 09:01
(Received via mailing list)
Logan Capaldo wrote:
> accessing the passed in function (block) anonymously.
> f1 { puts "Does the same thing" }
I see. So that was equivalent to:

  let rec nest ?(n=2) x f =
    Seq.fold (fun acc -> f acc) x {1 .. n}

but what is the meaning of the "_" in the Ruby "|acc, _|"?
86e33dee4a89a8879a26487051c216a8?d=identicon&s=25 Michael Fellinger (Guest)
on 2007-05-29 09:18
(Received via mailing list)
some people use _ as a temporary meaningless variable, just a
throw-away so to say.
In this case something like

hash = {:a => :b, :c => :d}

and you are not interested in the :b and :d

hash.each do |key, _|
  p key
end

I'm not necessarily a friend of this technique, but it seems easy on
the minds of some people.

^ manveru
827b1643b9e1ac6af6a9341db5bd3f6a?d=identicon&s=25 Jon Harrop (Guest)
on 2007-05-29 12:56
(Received via mailing list)
Michael Fellinger wrote:
> end
>
> I'm not necessarily a friend of this technique, but it seems easy on
> the minds of some people.

Right, this is exactly what I guessed it was doing (it is the same in
SML/OCaml/F#) but what value was being thrown away in the Ruby program
and
where did it come from?

  (1..n).inject(x) { |acc, _| yield(acc) }
97550977337c9f0a0e1a9553e55bfaa0?d=identicon&s=25 Jano Svitok (Guest)
on 2007-05-29 13:08
(Received via mailing list)
On 5/29/07, Jon Harrop <jon@ffconsultancy.com> wrote:
> >   p key
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy
> The F#.NET Journal
> http://www.ffconsultancy.com/products/fsharp_journal/?usenet

inject takes a block with two parameters. classic example is a sum of an
array:

array.inject(0) {|sum, item| sum + item }

so, in this case, item is not needed, so it is replaced by a variable
with name of "_"
that by convention means "temporary", "throw away"

it can be anything else:
(1..n).inject(x) { |acc, i_dont_need_this| yield(acc) }
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-29 13:15
(Received via mailing list)
On 29.05.2007 13:07, Jano Svitok wrote:
>> > hash.each do |key, _|
>>
> array.inject(0) {|sum, item| sum + item }
>
> so, in this case, item is not needed, so it is replaced by a variable
> with name of "_"
> that by convention means "temporary", "throw away"
>
> it can be anything else:
> (1..n).inject(x) { |acc, i_dont_need_this| yield(acc) }

Actually, #inject does not really make sense in this case.  All that
happens here is that some value is yielded n times to a block.  That
could have been done much more concise like this:

n.times { yield x }

Kind regards

  robert
96931bfe0c2948f47a98e15ae52e5637?d=identicon&s=25 Chris Carter (cdcarter)
on 2007-05-29 13:59
(Received via mailing list)
On 5/29/07, Robert Klemme <shortcutter@googlemail.com> wrote:
> >> >
> >> where did it come from?
> >
> happens here is that some value is yielded n times to a block.  That
> could have been done much more concise like this:
>
> n.times { yield x }
>
> Kind regards
>
>         robert
>
>

Actually, If it does what I think it does, the inject is needed
because as we know, inject sets the value returned from the block as
the accumulator for the next round.  Therefore:
>> nest(2) {|x| p x; [22] }
2
[22]
=> [22]
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-29 14:15
(Received via mailing list)
On 29.05.2007 13:59, Chris Carter wrote:
>> >> > and you are not interested in the :b and :d
>> >> and
>> of an
>>
>>
>
> Actually, If it does what I think it does, the inject is needed
> because as we know, inject sets the value returned from the block as
> the accumulator for the next round.  Therefore:
>>> nest(2) {|x| p x; [22] }
> 2
> [22]
> => [22]

Stupid me.  Of course you are right.  I should have taken more time to
digest this - or have more coffee.  Thank you for correcting me!

Kind regards

  robert
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-29 14:26
(Received via mailing list)
On 29.05.2007 14:11, Robert Klemme wrote:
>>> >> >
>>> >> Right, this is exactly what I guessed it was doing (it is the same in
>>> >> http://www.ffconsultancy.com/products/fsharp_journal/?usenet
>>> >
>>>
>> => [22]
>
> Stupid me.  Of course you are right.  I should have taken more time to
> digest this - or have more coffee.  Thank you for correcting me!

I was too fast (again).  Even though the return value is used, I'd
rather do

n.times { x = yield x }

than using #inject which does more than needed in this case.  :-)

Now, did I look at all aspects...?

Kind regards

  robert
Dd76a12d66f843de5c5f8782668e7127?d=identicon&s=25 Mauricio Fernandez (Guest)
on 2007-05-29 14:41
(Received via mailing list)
On Tue, May 29, 2007 at 07:55:05PM +0900, Jon Harrop wrote:
> >   p key
> > end
> >
> > I'm not necessarily a friend of this technique, but it seems easy on
> > the minds of some people.
>
> Right, this is exactly what I guessed it was doing (it is the same in
> SML/OCaml/F#) but what value was being thrown away in the Ruby program and
> where did it come from?
>
>   (1..n).inject(x) { |acc, _| yield(acc) }

You can read that as

 let l = range 1 n in
   List.fold_left (fun acc _ -> f acc) (List.hd l) (List.tl l)

f being the function corresponding to the implicit block called by
yield, and
range : int -> int -> int list.

Actually, in Ruby 1..n is a Range object which responds to the #inject
message
without creating an intermediate array, and the #inject method is
implemented
elsewhere, so the above works a bit like this:


let val_of = function
    Some x -> x
  | None -> failwith "val_of"

(* In Ruby, Enumerable is a module that can be included ("mixin") into
 * classes that define an #each method. It provides many useful methods
like
 * #map, #find, #find_all, #reject, #max, #min, #sort, #sort_by,
#partition,
 * #each_with_index, #include?... built atop #each.*)
class virtual ['value] enumerable =
object(self: 'b)
  method virtual each : ('value -> unit) -> 'b (* returning self allows
to
                                                * chain method calls *)

  method inject :
    (* Ruby behaves like
     *  'acc. ?first_value:'acc -> ('acc -> 'value -> 'acc) -> 'acc =
     * but this doesn't type in ocaml since we'll pass the first
     * value (:'value) to f if no first_value is given, forcing
     * 'acc = 'value.
     *)
    ?first_value:'value -> ('value -> 'value -> 'value) -> 'value =
      fun ?first_value f ->
        let acc = ref first_value in
          (* written this way to mimic Ruby's implementation,
           * which uses an accumulator initialized to Qundef *)
          ignore (self#each (fun x ->
                               match !acc with
                                   None -> acc := Some x
                                 | Some v -> acc := Some (f v x)));
          val_of !acc
end

class ['value] range (first : 'value) (last : 'value) succ inclusive =
object(self)
  inherit ['value] enumerable
  (* this gives us lots of methods implemented using #each *)

  val upper_bound : 'value = if inclusive then succ last else last

  method each f =
    let rec loop v =
      if v < upper_bound then (f v; loop (succ v))
    in
      loop first;
      self
end

let _ =
  (* r = 1..10 *)
  let r = new range 1 10 succ true in
  (* r = 1...10  would be  new range 1 10 succ false *)
    Printf.printf "%d %d\n"
      (* r.inject{|s,_| s * 2} *)
      (r#inject (fun s _ -> s * 2))
      (* r.inject(10){|s,_| s * 2} *)
      (r#inject ~first_value:10 (fun s _ -> s * 2))


Of course, being dynamically typed, Ruby doesn't have/need parameterized
classes, and instead of using a succ function, Range#each repeatedly
calls the
#succ method of the lower bound.

One last note: while things like #inject are as powerful as their OCaml
counterparts (and more convenient thanks to dynamic typing, but you know
there's a price for that...), they are often slower than simpler
iteration
methods:

  require 'benchmark'

  Benchmark.bm(10) do |bm|
    a = (0..10000).to_a # create an array with values 0 to 10000

    bm.report("each") do
      100.times { sum = 0; a.each{|x| sum += x}; sum }
    end

    bm.report("inject") { 100.times { a.inject{|s,x| s + x} } }
  end

  # >>                 user     system      total        real
  # >> each        0.610000   0.000000   0.610000 (  0.618960)
  # >> inject      1.800000   0.020000   1.820000 (  1.850604)
(yes, it really is that slow)

Also, Ruby doesn't optimize tail calls, so you cannot write the sort of
recursive functions OCaml excels at. OTOH, the core classes provide much
more
functionality, and more often than not the existing higher-order
functions
will fit the bill.
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2007-05-30 00:50
(Received via mailing list)
On 5/29/07, Robert Klemme <shortcutter@googlemail.com> wrote:
>
>
> I was too fast (again).  Even though the return value is used, I'd rather
> do
>
> n.times { x = yield x }
>
> than using #inject which does more than needed in this case.  :-)
>
> Now, did I look at all aspects...?


Almost.
you'd actually need
n.times { x = yield x }
x


Kind regards
827b1643b9e1ac6af6a9341db5bd3f6a?d=identicon&s=25 Jon Harrop (Guest)
on 2007-05-30 04:12
(Received via mailing list)
Mauricio Fernandez wrote:
> You can read that as
>
>  let l = range 1 n in
>    List.fold_left (fun acc _ -> f acc) (List.hd l) (List.tl l)

Oh, of course! The ignored argument is the number 1 .. n.

> Actually, in Ruby 1..n is a Range object which responds to the #inject
> message without creating an intermediate array,

Laziness, yep.

> ...
> class ...

You wouldn't use objects to do this in OCaml though. If you wanted to
fold
over a data structure you'd just write:

  let nest n f x = fold (fun x _ -> f x) x {1 .. n}

> Of course, being dynamically typed, Ruby doesn't have/need parameterized
> classes, and instead of using a succ function, Range#each repeatedly calls
> the #succ method of the lower bound.

I don't think parameterized classes are needed here.

If you want it more dynamic (generic over kind of data structure, for
example), you might write:

  let nest n f x = {1 .. n}#fold (fun x _ -> f x) x

but I've never used this style in practice (you always know what data
structure you're dealing with).

> One last note: while things like #inject are as powerful as their OCaml
> counterparts (and more convenient thanks to dynamic typing, but you know
> there's a price for that...), they are often slower than simpler iteration
> methods:

There is a similar overhead in OCaml (for polymorphic HOFs).

>   # >>                 user     system      total        real
>   # >> each        0.610000   0.000000   0.610000 (  0.618960)
>   # >> inject      1.800000   0.020000   1.820000 (  1.850604)
> (yes, it really is that slow)
>
> Also, Ruby doesn't optimize tail calls, so you cannot write the sort of
> recursive functions OCaml excels at. OTOH, the core classes provide much
> more functionality, and more often than not the existing higher-order
> functions will fit the bill.

I think this is equivalent:

# let time f x =
    let t = Sys.time() in
    let f_x = f x in
    Printf.printf "Time: %f\n%!" (Sys.time() -. t);
    f_x;;
val time : ('a -> 'b) -> 'a -> 'b = <fun>
# let rec loop n f x = if n>0 then (ignore(f x); loop (n-1) f x);;
val loop : int -> ('a -> 'b) -> 'a -> unit = <fun>
# let a = Array.init 10000 (fun i -> i);;
...
# time (loop 100 (fun a -> Array.fold_left (+) 0 a)) a;;
Time: 0.203969
- : unit = ()

So the interpreted OCaml bytecode is ~6x faster and compiled OCaml is
~260x
faster.

Thanks for all the help!
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (Guest)
on 2007-05-30 09:28
(Received via mailing list)
On Wed, May 30, 2007 at 07:50:05AM +0900, Logan Capaldo wrote:
> >Now, did I look at all aspects...?
>
>
> Almost.
> you'd actually need
> n.times { x = yield x }
> x

Almost almost :-)

x = nil
n.times { x = yield x }
x
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-30 10:41
(Received via mailing list)
On 5/30/07, Brian Candler <B.Candler@pobox.com> wrote:
> > >
> x = nil
> n.times { x = yield x }
> x
>
>
Robert was very quick indeed, he did not repeat the context of the
expression which was

def forgot_the_name(x,...)
    n.times{ x = yield x }
end

Now it works ;)
I still fail to see what the array was used for ;)

Robert
Dd76a12d66f843de5c5f8782668e7127?d=identicon&s=25 Mauricio Fernandez (Guest)
on 2007-05-30 12:02
(Received via mailing list)
On Wed, May 30, 2007 at 11:10:21AM +0900, Jon Harrop wrote:
> over a data structure you'd just write:
>
>   let nest n f x = fold (fun x _ -> f x) x {1 .. n}

Indeed; I was just illustrating a part of Ruby's object model (mixins)
with
OCaml code.

BTW, is {1.. n} a F# range comprehension or have you written some camlp4
extension that looks like that (or is it only pseudocode)?

> I think this is equivalent:
[...]
> # time (loop 100 (fun a -> Array.fold_left (+) 0 a)) a;;
> Time: 0.203969
> - : unit = ()
>
> So the interpreted OCaml bytecode is ~6x faster and compiled OCaml is ~260x
> faster.

On a rather old box, ocaml runs that in 0.28s (vs. Ruby's 0.61s with
#each,
#1.8s with inject), and an imperative expansion (with for and a ref) in
0.17s,
so the ratios are
 fold_left/inject     6.4X
 imperative           3.6X
HOFs in Ruby are often more expensive than they would be in OCaml
because
method and especially block (anonymous function) calls are quite slow.

However, on Ruby 1.9, still under development and expected to be
released by
xmas 2007:

$ ruby19 -v bm.rb
ruby 1.9.0 (2007-02-07 patchlevel 0) [i686-linux]
                user     system      total        real
each        0.230000   0.000000   0.230000 (  0.228493)
inject      0.310000   0.000000   0.310000 (  0.313735)

making it comparable to OCaml's bytecode, which is hardly surprising
since
they are both stack machines with threaded code/computed gotos.
827b1643b9e1ac6af6a9341db5bd3f6a?d=identicon&s=25 Jon Harrop (Guest)
on 2007-05-30 13:31
(Received via mailing list)
Mauricio Fernandez wrote:
> Indeed; I was just illustrating a part of Ruby's object model (mixins)
> with OCaml code.

Right.

> BTW, is {1.. n} a F# range comprehension or have you written some camlp4
> extension that looks like that (or is it only pseudocode)?

Both. Native to F# and I think someone implemented it as a camlp4 macro
for
OCaml. However, containers are not derived from sequences in OCaml as
they
are in F#. You'd have to wrap them in objects yourself and people aren't
likely to do that. For one thing, lists are slower in F# as a
consequence.

> However, on Ruby 1.9, still under development and expected to be released
> by xmas 2007:
>
> $ ruby19 -v bm.rb
> ruby 1.9.0 (2007-02-07 patchlevel 0) [i686-linux]
>                 user     system      total        real
> each        0.230000   0.000000   0.230000 (  0.228493)
> inject      0.310000   0.000000   0.310000 (  0.313735)
>
> making it comparable to OCaml's bytecode, which is hardly surprising since
> they are both stack machines with threaded code/computed gotos.

Yes. Is there a native-code compiler for Ruby in the works? Does the
.NET
implementation give much better performance?
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2007-05-30 22:27
(Received via mailing list)
On 5/30/07, Robert Dober <robert.dober@gmail.com> wrote:
> > > >n.times { x = yield x }
> >
> def forgot_the_name(x,...)
>     n.times{ x = yield x }


      Still need x here

end
>
> Now it works ;)


No it doesn't ;)  n.times {  ... } returns n.

I still fail to see what the array was used for ;)
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-30 22:37
(Received via mailing list)
On 5/30/07, Logan Capaldo <logancapaldo@gmail.com> wrote:
> > > > >
> > > > x
> >
>
> No it doesn't ;)  n.times {  ... } returns n.
Obviously I am too stupid to test, sorry, I did test it, who knows how
;)
Seriously I do know now, n just was the expected result of the block :(

def anyhow(count, x)
  count.times{x=yield x}
  x
end

Maybe we can still agree that this is better than inspect ;)
And yes thanks for the Ruby classes I got.

Cheers
Robert
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-31 10:56
(Received via mailing list)
On 30.05.2007 22:36, Robert Dober wrote:
>> > > > >do
>> > > > n.times { x = yield x }
>> > expression which was
>>
> Maybe we can still agree that this is better than inspect ;)
> And yes thanks for the Ruby classes I got.

Hm...  Thinking a bit more about this I am not sure I'd stick with my
proposal.  I think I'd probably do

irb(main):001:0> require 'enumerator'
=> true
irb(main):002:0> def rep(n,init=nil) n.to_enum(:times).inject(init)
{|x,| yield x} end
=> nil
irb(main):003:0> rep(5,"x") {|s| puts s; s<<"."}
x
x.
x..
x...
x....
=> "x....."

Hmm...

Kind regards

  robert
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-31 11:52
(Received via mailing list)
On 5/31/07, Robert Klemme <shortcutter@googlemail.com> wrote:
> >> > rather
> >> > > > you'd actually need
> >> > Robert was very quick indeed, he did not repeat the context of the
> >> > Now it works ;)
> >
> => nil
> irb(main):003:0> rep(5,"x") {|s| puts s; s<<"."}
> x
> x.
> x..
> x...
> x....
> => "x....."
>
> Hmm...
As we are fooling around ;)

class Integer
  alias_method :good_old_times, :times
  def times
    r = nil
    good_old_times do
      |n|
      r = Proc.new.call n
    end
    r
  end

  def rep init = nil
    times do
       init = Proc.new.call init
    end
  end
end


puts 5.times{ |x| 2*x }
puts 5.rep(12){ |x| x+1 }
BTW what is this good for anyway ;) for loops???

Cheers
Robert
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-31 13:10
(Received via mailing list)
On 31.05.2007 11:51, Robert Dober wrote:
>> >> > > > >I was too fast (again).  Even though the return value is
>> >> > > >
>> >> > > x
>> >>
>> > def anyhow(count, x)
>> irb(main):001:0> require 'enumerator'
>> => "x....."
>      r = Proc.new.call n
>    end
>    r
>  end

You are aware that this does something different, especially will it
return the last block value only.

Also, why do you use Proc.new.call instead of yield?

> BTW what is this good for anyway ;) for loops???
Probably.  I tend to believe that usually #inject is better for
calculations that involve repetition and want to process the result of
the last calculation.  Usually I don't think that the iteration value is
ignored in such cases.  Maybe the OP had a specific example in mind.

The initial question was what does the underscore do in

def nest(x, n = 2)
   (1..n).inject(x) { |acc, _| yield(acc) }
end

Basically it's completely superfluous, you can do this instead:

def nest(x, n = 2)
   (1..n).inject(x) { |acc,| yield acc }
end

Btw, I'd rather change the argument handling because n=2 is a pretty
arbitrary default.

def nest(n, x = nil)
   (1..n).inject(x) { |acc,| yield acc }
end

Kind regards

  robert
Dd76a12d66f843de5c5f8782668e7127?d=identicon&s=25 Mauricio Fernandez (Guest)
on 2007-06-01 11:54
(Received via mailing list)
On Wed, May 30, 2007 at 08:30:13PM +0900, Jon Harrop wrote:
> > making it comparable to OCaml's bytecode, which is hardly surprising since
> > they are both stack machines with threaded code/computed gotos.
>
> Yes. Is there a native-code compiler for Ruby in the works? Does the .NET
> implementation give much better performance?

Nothing has been heard about a native code compiler (Ruby makes it
challenging
for a number of reasons).

AFAIK at this point in time the alternative implementations are all
slower or
a bit faster at best than the standard interpreter.

Microsoft's IronRuby hasn't been released yet, so nothing is known about
its
performance or the degree of compatibility with Ruby 1.8.  The most
recent
IronPython vs. CPython benchmark I've found[1] reveals that the former
is not
faster than the latter. If IronRuby performs similarly, it might come
relatively close to Ruby 1.9 (formerly known as YARV), but it doesn't
look
like it will improve significantly on it.

[1]
http://lists.ironpython.com/pipermail/users-ironpy...
827b1643b9e1ac6af6a9341db5bd3f6a?d=identicon&s=25 Jon Harrop (Guest)
on 2007-06-02 09:41
(Received via mailing list)
Mauricio Fernandez wrote:
> The most recent
> IronPython vs. CPython benchmark I've found[1] reveals that the former is
> not faster than the latter.

Wow. That's absolutely fascinating.

I've put a lot of effort into learning the new F# programming language
from
Microsoft Research. It is derived from the Caml family of functional
programming languages and suffers from similar performance trade-offs
taken
by .NET:

1. Allocation is much slower because the .NET allocator is designed to
work
with object lifetime distributions typical of C#.

2. Exceptions are 600x slower on .NET and exceptions are ubiquitous in
OCaml, used extensively by the stdlib for common cases (e.g. not finding
an
element in a dictionary).

3. Tail calls are also ubiquitous in functional languages and they are
many
times slower on the .NET platform. You can ask the compiler to use
non-tail
calls but then you run the risk of blowing stack.

So the differences between OCaml and F# hit worst case in a wide variety
of
real situations. Very interesting to see that the performance
differences
are so huge that they even affect interpreted languages. I would not
have
expected that.
This topic is locked and can not be replied to.