anonymous closures with Proc,new, lambda and ->

Discussion in 'Ruby' started by Stu, Apr 19, 2011.

  1. Stu

    Stu Guest

    [Note: parts of this message were removed to make it a legal post.]

    I am new to the study of functional paradigm. If this question is academic
    please bear with me.

    How would I make this counter with lambda or -> without deferring to a named
    generator method or sigil var?

    my ruby version:

    % ruby -v
    ruby 1.9.2p180 (2011-02-18 revision 30907)

    my code examples for explanation:

    % irb
    >> closed = Proc.new( over=0){over+=1}

    => #<Proc:0x00000001300e98@(irb):10>
    >> 4.times { puts closed[] }

    1
    2
    3
    4
    => 4

    error out on lambda

    >> closed = lambda( over=0){over+=1}

    ArgumentError: wrong number of arguments(1 for 0)
    ...

    and -> doesn't error but give undesired results:

    >> closed = ->( over=0){over+=1}

    => #<Proc:0x00000001234d20@(irb):16 (lambda)>

    >> 4.times { puts closed[] }

    1
    1
    1
    1
    => 4

    in a named method I relize I can use a named method with argument being
    bound while returning with either -> or lamda. for example:

    def closure( over=0) lambda{over+=1} end
    def closure( over=0) ->{over+=1} end

    closed = closure

    both of these will work. I am just curious if there is a way to accomplish
    the same thing without method name definition i.e anonymous function.
     
    Stu, Apr 19, 2011
    #1
    1. Advertising

  2. On Tue, Apr 19, 2011 at 8:07 AM, Stu <> wrote:
    > I am new to the study of functional paradigm. If this question is academi=

    c
    > please bear with me.
    >
    > How would I make this counter with lambda or -> without deferring to a na=

    med
    > generator method or sigil var?
    >
    > my ruby version:
    >
    > % =A0ruby -v
    > ruby 1.9.2p180 (2011-02-18 revision 30907)
    >
    > my code examples for explanation:
    >
    > % irb
    >>> closed =3D Proc.new( over=3D0){over+=3D1}

    > =A0=3D> #<Proc:0x00000001300e98@(irb):10>
    > =A0>> 4.times { puts closed[] }
    > 1
    > 2
    > 3
    > 4
    > =A0=3D> 4


    That might not work as you expect:

    09:22:04 ~$ ruby19 -e 'closed=3DProc.new(over=3D0){over+=3D1};2.times{p
    closed[]};p over;over=3D-1;2.times{p closed[]}'
    1
    2
    2
    0
    1
    09:22:19 ~$

    Please see below for explanation. (And btw, when it comes to local
    variables it's usually better to not test in IRB since that behaves a
    bit differently there.)

    > error out on =A0lambda
    >
    >>> closed =3D lambda( over=3D0){over+=3D1}

    > ArgumentError: wrong number of arguments(1 for 0)
    > ...
    >
    > and -> doesn't error but give undesired results:
    >
    >>> closed =3D ->( over=3D0){over+=3D1}

    > =A0=3D> #<Proc:0x00000001234d20@(irb):16 (lambda)>
    >
    >>> 4.times { puts closed[] }

    > 1
    > 1
    > 1
    > 1
    > =A0=3D> 4
    >
    > in a named method I relize I can use a named method with argument being
    > bound while returning with either -> or lamda. for example:
    >
    > def closure( over=3D0) lambda{over+=3D1} end
    > def closure( over=3D0) ->{over+=3D1} end
    >
    > closed =3D closure
    >
    > both of these will work. I am just curious if there is a way to accomplis=

    h
    > the same thing without method name definition i.e anonymous function.


    The point is that for a closure to be created you need a scope. In
    your first case you basically do the same as

    over=3D0
    closed =3D Proc.new{over+=3D1}

    In other words: you use the current scope. But only if you use a
    method or another lambda you can ensure that the scope is not visible
    any more to the outside world and is only accessible through the
    closure. And this is what one usually wants because otherwise the
    data can be manipulated from outside the closure which might break the
    desired functionality (such as resetting a counter as shown above).

    With these approaches you get a scope which is cut off and not
    accessible from the outside:

    09:28:05 ~$ ruby19 -e 'def m(x=3D0)lambda {x+=3D1}end;f=3Dm;2.times{p f[]}'
    1
    2
    09:28:14 ~$ ruby19 -e 'm=3Dlambda{|x=3D0| lambda {x+=3D1}};f=3Dm[];2.times{=
    p f[]}'
    1
    2
    09:28:19 ~$

    Kind regards

    robert

    --=20
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, Apr 19, 2011
    #2
    1. Advertising

  3. Stu wrote in post #993687:
    > I am new to the study of functional paradigm. If this question is
    > academic
    > please bear with me.
    >
    > How would I make this counter with lambda or -> without deferring to a
    > named
    > generator method or sigil var?


    Starting with the "named generator method":

    def make_counter(init)
    lambda { init += 1 }
    end

    Calling that method creates a new scope, and binds the value of 'init'
    within that scope.

    Now, you can do the same without def, by wrapping in another lambda:

    counter_maker = lambda { |init| lambda { init += 1 } }
    c = counter_maker.call(100)
    c.call # 101
    c.call # 102

    And you can do the same without explicitly binding 'counter_maker'
    either:

    c = lambda { |init| lambda { init += 1 } }.call(200)
    c.call # 201
    c.call # 202

    Is that what you were looking for?

    --
    Posted via http://www.ruby-forum.com/.
     
    Brian Candler, Apr 19, 2011
    #3
  4. Brian Candler wrote in post #993704:
    > And you can do the same without explicitly binding 'counter_maker'
    > either:
    >
    > c = lambda { |init| lambda { init += 1 } }.call(200)
    > c.call # 201
    > c.call # 202


    Which of course simplifies to:

    c = lambda { init = 200; lambda { init += 1 } }.call
    c.call # 201
    c.call # 202

    The outer lambda here is just to ensure that 'init' is in its own scope,
    so if you run this code multiple times, each lambda returned has an
    independent instance of 'init'

    Note: this only works as long as 'init' hasn't already been seen
    outside; if it has, all the lambdas will bind to the same 'init'.

    In ruby 1.9 there's a way to force it to be local:

    c = lambda { |;init| init = 200; ...etc... }.call

    But in that case the original code would be shorter:

    c = lambda { |init| ...etc... }.call(200)

    This does the same in 1.9 (because block parameters are always local),
    but in 1.8 it would still bind to the outside 'init' variable if one
    exists.

    --
    Posted via http://www.ruby-forum.com/.
     
    Brian Candler, Apr 19, 2011
    #4
  5. Stu

    Stu Guest

    [Note: parts of this message were removed to make it a legal post.]

    On Tue, Apr 19, 2011 at 3:15 AM, Brian Candler <> wrote:

    > Brian Candler wrote in post #993704:
    >
    > In ruby 1.9 there's a way to force it to be local:
    >
    > c = lambda { |;init| init = 200; ...etc... }.call
    >
    >
    >

    What does the semicolon tell the interpreter here? init now exists outside
    the closure scope? in this case main?
     
    Stu, Apr 19, 2011
    #5
  6. Stu wrote in post #993715:
    >> c = lambda { |;init| init = 200; ...etc... }.call
    >>
    >>
    >>

    > What does the semicolon tell the interpreter here?


    It's a block-local variable. You can think of it as a block argument
    which is never passed by the caller, so always gets nil. Compare:

    c = lambda { |init| ... } # init is local, value is passed

    c = lambda { |init;x,y| ... } # init is local, value is passed;
    # x and y are local, no value passed

    So given:

    init = 123
    c = lambda { |;init| init = 456; ... }
    puts init # 123

    then the 'init' inside the lambda is always a different 'init' to the
    one outside. Any arguments which the lambda took would come before the
    semicolon, but there are zero in this case.

    For more info google "ruby block local variables"

    IMO it ranks with '->' as an ugly and unnecessary bit of 1.9 syntax, but
    tastes vary. See what you think of:

    c = ->(;init) { init=100; ->{init += 1} }.call

    Regards,

    Brian.

    --
    Posted via http://www.ruby-forum.com/.
     
    Brian Candler, Apr 19, 2011
    #6
  7. Stu

    7stud -- Guest

    7stud --, Apr 19, 2011
    #7
  8. 7stud -- wrote in post #993798:
    > Where does this syntax come from?
    >
    > closed = Proc.new(over=0){over+=1}


    It's invalid in 1.8:

    >> Proc.new(0) {}

    ArgumentError: wrong number of arguments (1 for 0)
    from (irb):2:in `initialize'
    from (irb):2:in `new'
    from (irb):2
    from :0

    But accepted in 1.9.2:

    >> Proc.new(0) {}

    => #<Proc:0x000000023cc380@(irb):1>

    Seems to be undocumented, like much of ruby 1.9.
    http://ruby-doc.org/core/classes/Proc.html

    I can't see any obvious purpose for these args:

    irb(main):006:0> c = Proc.new(1,2,3) { |x,y,z| p x,y,z }
    => #<Proc:0x00000001f17920@(irb):6>
    irb(main):007:0> c.call(5)
    5
    nil
    nil
    => [5, nil, nil]

    --
    Posted via http://www.ruby-forum.com/.
     
    Brian Candler, Apr 19, 2011
    #8
  9. Steve Klabnik, Apr 19, 2011
    #9
  10. Interesting. The default allocation behavior method is removed, and =
    Class.new is overridden, which uses custom allocation and forwards =
    arguments to #initialize - just like normal Class.new. Except Proc =
    doesn't implement #initialize, so it bubbles up to Object#initialize. =
    Since Object#initialize just takes any number of arguments and ignores =
    them, providing an argument to Proc.new doesn't raise.

    It seems adding an empty, 0-arg #initialize method to Proc doesn't =
    really lose anything here, and would catch mistakes. The only tiny =
    downside would be a miniscule slow down on explicit calls to Proc.new... =
    which I think most Rubyists can live with.

    Michael Edgar

    http://carboni.ca/

    On Apr 19, 2011, at 2:26 PM, Steve Klabnik wrote:

    > Doesn't look like it's really used for anything:
    > https://github.com/ruby/ruby/blob/trunk/proc.c#L448
     
    Michael Edgar, Apr 19, 2011
    #10
  11. [Note: parts of this message were removed to make it a legal post.]

    On Tue, Apr 19, 2011 at 1:24 PM, Brian Candler <> wrote:

    > then the 'init' inside the lambda is always a different 'init' to the
    > one outside. Any arguments which the lambda took would come before the
    > semicolon, but there are zero in this case.
    >
    > For more info google "ruby block local variables"
    >


    A nice example is given on Read Ruby 1.9:
    http://ruby.runpaint.org/closures#block-local-variables

    Usually the section I go to when I need a reminder.
     
    Adam Prescott, Apr 19, 2011
    #11
  12. Stu

    Stu Guest

    [Note: parts of this message were removed to make it a legal post.]

    how would i break it down to two functions?

    example:
    >> inc = lambda {|n|n+=1}

    => #<Proc:0x00000100926318@(irb):23 (lambda)>

    >> counter = lambda {n=1; n=inc.call(n)}.call(&inc)

    => 2

    >> counter[]

    ArgumentError: wrong number of arguments(0 for 1)


    On Tue, Apr 19, 2011 at 3:15 AM, Brian Candler <> wrote:

    > Brian Candler wrote in post #993704:
    > > And you can do the same without explicitly binding 'counter_maker'
    > > either:
    > >
    > > c = lambda { |init| lambda { init += 1 } }.call(200)
    > > c.call # 201
    > > c.call # 202

    >
    > Which of course simplifies to:
    >
    > c = lambda { init = 200; lambda { init += 1 } }.call
    > c.call # 201
    > c.call # 202
    >
    >
     
    Stu, Apr 19, 2011
    #12
  13. Stu

    7stud -- Guest

    Stu wrote in post #993854:
    >



    inc = lambda {|n| n+=1}

    counter = lambda do |a_proc|
    n = 1
    n = a_proc.call(n)

    end.call(inc)

    puts counter

    --output:--
    2

    --
    Posted via http://www.ruby-forum.com/.
     
    7stud --, Apr 20, 2011
    #13
  14. Stu

    7stud -- Guest

    Stu wrote in post #993854:
    > how would i break it down to two functions?



    Is this what you are looking for:

    inc = lambda do
    n = 1
    lambda{n += 1}
    end.call

    counter = lambda{inc.call}
    puts counter[]
    puts counter[]

    --output:--
    2
    3

    --
    Posted via http://www.ruby-forum.com/.
     
    7stud --, Apr 20, 2011
    #14
  15. Stu

    Stu Guest

    [Note: parts of this message were removed to make it a legal post.]

    Lots of helpful information in this thread. Thank you all for helping me.

    Since I am new to functional programming I am slowly experimenting with what
    I know and building slowly from there. In the same fashion that object
    oriented is no more than the sum of it's parts I am interested in learning
    as much as I can about this paradigm.

    I understand the concept of closure. I imagine the best use for it would be
    to build one and embed it in another and so one( correct me if I'm wrong)

    I have read and experimented with ruby's Proc#curry method. There is a
    tutorial online which explains haskell's monads in ruby I plan on grokking
    as well.

    Are there any other facets of functional programming theory I should look at
    to take advantage of?

    On Tue, Apr 19, 2011 at 9:28 PM, 7stud -- <> wrote:

    > Stu wrote in post #993854:
    > > how would i break it down to two functions?

    >
    >
    > Is this what you are looking for:
    >
    > inc = lambda do
    > n = 1
    > lambda{n += 1}
    > end.call
    >
    > counter = lambda{inc.call}
    > puts counter[]
    > puts counter[]
    >
    > --output:--
    > 2
    > 3
    >
    > --
    > Posted via http://www.ruby-forum.com/.
    >
    >
     
    Stu, Apr 20, 2011
    #15
  16. On Wed, Apr 20, 2011 at 8:03 AM, Stu <> wrote:
    > Lots of helpful information in this thread. Thank you all for helping me.


    You're welcome!

    > Since I am new to functional programming I am slowly experimenting with what
    > I know and building slowly from there. In the same fashion that object
    > oriented is no more than the sum of it's parts I am interested in learning
    > as much as I can about this paradigm.


    In my understanding closures are not that essential for FP - at least
    not for storing data. The Wikipedia article sums the core properties
    of FP up pretty good IMHO:

    "[...] functional programming is a programming paradigm that treats
    computation as the evaluation of mathematical functions and avoids
    state and mutable data. It emphasizes the application of functions,
    in contrast to the imperative programming style, which emphasizes
    changes in state."

    http://en.wikipedia.org/wiki/Functional_programming

    Also a frequently seen feature is first class and higher order functions.
    http://en.wikipedia.org/wiki/Higher-order_function
    http://en.wikipedia.org/wiki/First-class_function

    > I understand the concept of closure. I imagine the best use for it would be
    > to build one and embed it in another and so one( correct me if I'm wrong)


    That entirely depends on the use case. With currying that is
    certainly what happens.

    > I have read and experimented with ruby's Proc#curry method. There is a
    > tutorial online which explains haskell's monads in ruby I plan on grokking
    > as well.
    >
    > Are there any other facets of functional programming theory I should look at
    > to take advantage of?


    One interesting thing that you can take away from FP is that some
    things do get easier even in OO if you avoid side effects. For
    example concurrency has less issues if objects are immutable. Of
    course the downside is that you pay with GC overhead and frozen
    instances in some way go against the paradigm of OO because one of the
    major aspects of OO is encapsulation of state with functionality; and
    this typically means _mutable state_. But on the other hand in
    certain areas (e.g numbers and arithmetic) the concept of immutable
    state is quite common in OO languages (Ruby and Java both have it).

    If you really want to dive deeper into FP you should probably not use
    Ruby but rather a first class FP language. I won't recommend one
    because others know that area far better than I do. There were some
    recommendations recently:

    http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-talk/380949?380902-381876

    You can also find a pretty neat list here:
    http://www.cs.nott.ac.uk/~gmh/faq.html

    Kind regards

    robert

    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, Apr 20, 2011
    #16
  17. [Note: parts of this message were removed to make it a legal post.]

    I would highly reccommend Haskell, and http://learnyouahaskell.com/ .
    On Apr 20, 2011 3:24 AM, "Robert Klemme" <> wrote:
    > On Wed, Apr 20, 2011 at 8:03 AM, Stu <> wrote:
    >> Lots of helpful information in this thread. Thank you all for helping me.

    >
    > You're welcome!
    >
    >> Since I am new to functional programming I am slowly experimenting with

    what
    >> I know and building slowly from there. In the same fashion that object
    >> oriented is no more than the sum of it's parts I am interested in

    learning
    >> as much as I can about this paradigm.

    >
    > In my understanding closures are not that essential for FP - at least
    > not for storing data. The Wikipedia article sums the core properties
    > of FP up pretty good IMHO:
    >
    > "[...] functional programming is a programming paradigm that treats
    > computation as the evaluation of mathematical functions and avoids
    > state and mutable data. It emphasizes the application of functions,
    > in contrast to the imperative programming style, which emphasizes
    > changes in state."
    >
    > http://en.wikipedia.org/wiki/Functional_programming
    >
    > Also a frequently seen feature is first class and higher order functions.
    > http://en.wikipedia.org/wiki/Higher-order_function
    > http://en.wikipedia.org/wiki/First-class_function
    >
    >> I understand the concept of closure. I imagine the best use for it would

    be
    >> to build one and embed it in another and so one( correct me if I'm wrong)

    >
    > That entirely depends on the use case. With currying that is
    > certainly what happens.
    >
    >> I have read and experimented with ruby's Proc#curry method. There is a
    >> tutorial online which explains haskell's monads in ruby I plan on

    grokking
    >> as well.
    >>
    >> Are there any other facets of functional programming theory I should look

    at
    >> to take advantage of?

    >
    > One interesting thing that you can take away from FP is that some
    > things do get easier even in OO if you avoid side effects. For
    > example concurrency has less issues if objects are immutable. Of
    > course the downside is that you pay with GC overhead and frozen
    > instances in some way go against the paradigm of OO because one of the
    > major aspects of OO is encapsulation of state with functionality; and
    > this typically means _mutable state_. But on the other hand in
    > certain areas (e.g numbers and arithmetic) the concept of immutable
    > state is quite common in OO languages (Ruby and Java both have it).
    >
    > If you really want to dive deeper into FP you should probably not use
    > Ruby but rather a first class FP language. I won't recommend one
    > because others know that area far better than I do. There were some
    > recommendations recently:
    >
    >

    http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-talk/380949?380902-381876
    >
    > You can also find a pretty neat list here:
    > http://www.cs.nott.ac.uk/~gmh/faq.html
    >
    > Kind regards
    >
    > robert
    >
    > --
    > remember.guy do |as, often| as.you_can - without end
    > http://blog.rubybestpractices.com/
    >
     
    Steve Klabnik, Apr 20, 2011
    #17
  18. Michael Edgar wrote in post #993817:
    > Proc
    > doesn't implement #initialize, so it bubbles up to Object#initialize.
    > Since Object#initialize just takes any number of arguments and ignores
    > them, providing an argument to Proc.new doesn't raise.


    So I think the question becomes: why does Object#initialize accept any
    number of arguments in 1.9? It doesn't in 1.8.

    $ ruby -ve 'Object.new(1,2,3)'
    ruby 1.8.7 (2010-06-23 patchlevel 299) [x86_64-linux]
    -e:1:in `initialize': wrong number of arguments (3 for 0)
    (ArgumentError)
    from -e:1:in `new'
    from -e:1
    $ ruby192 -ve 'Object.new(1,2,3)'
    ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]
    $

    --
    Posted via http://www.ruby-forum.com/.
     
    Brian Candler, Apr 20, 2011
    #18
  19. Stu

    7stud -- Guest

    Stu wrote in post #993922:
    > There is a
    > tutorial online which explains haskell's monads in ruby I plan on
    > grokking
    > as well.
    >


    It's my understanding that unless you have a Phd in abstract
    mathematical theory and are one of the inventors of String theory(M
    theory in particular), you will never understand monads.

    --
    Posted via http://www.ruby-forum.com/.
     
    7stud --, Apr 20, 2011
    #19
  20. Stu

    Jeremy Bopp Guest

    On 4/20/2011 10:18, Brian Candler wrote:
    > Michael Edgar wrote in post #993817:
    >> Proc
    >> doesn't implement #initialize, so it bubbles up to Object#initialize.
    >> Since Object#initialize just takes any number of arguments and ignores
    >> them, providing an argument to Proc.new doesn't raise.

    >
    > So I think the question becomes: why does Object#initialize accept any
    > number of arguments in 1.9? It doesn't in 1.8.


    It seems that it was a bit of an oversight when the change that
    implemented that feature was approved. This is the redmine issue that
    tracked the change:

    http://redmine.ruby-lang.org/issues/show/2451

    Here is a discussion about it:

    http://www.ruby-forum.com/topic/330466

    Apparently, the change was reverted for Ruby 1.9.3+. I haven't checked
    to confirm for myself yet.

    -Jeremy
     
    Jeremy Bopp, Apr 20, 2011
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. David Lozzi
    Replies:
    3
    Views:
    1,972
    David Lozzi
    Jun 1, 2005
  2. Louis Steinberg

    problem with lambda / closures

    Louis Steinberg, Nov 30, 2009, in forum: Python
    Replies:
    1
    Views:
    269
    Marco Mariani
    Nov 30, 2009
  3. Minkoo Seo

    Proc vs lambda vs proc

    Minkoo Seo, Feb 4, 2007, in forum: Ruby
    Replies:
    19
    Views:
    256
    Brian Candler
    Feb 6, 2007
  4. Steve Dogers

    lambda vs non-lambda proc

    Steve Dogers, Mar 30, 2009, in forum: Ruby
    Replies:
    1
    Views:
    194
    Sean O'Halpin
    Mar 30, 2009
  5. Thomas Hafner
    Replies:
    2
    Views:
    136
    Ryan Davis
    Apr 25, 2009
Loading...

Share This Page