anonymous closures with Proc,new, lambda and ->

S

Stu

[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}
=> # said:
4.times { puts closed[] }
1
2
3
4
=> 4

error out on lambda
ArgumentError: wrong number of arguments(1 for 0)
...

and -> doesn't error but give undesired results:
closed = ->( over=0){over+=1}
=> # said:
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.
 
R

Robert Klemme

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=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
ArgumentError: wrong number of arguments(1 for 0)
...

and -> doesn't error but give undesired results:
closed =3D ->( over=3D0){over+=3D1}
=A0=3D> # said:
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/
 
B

Brian Candler

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?
 
B

Brian Candler

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.
 
S

Stu

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

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?
 
B

Brian Candler

Stu wrote in post #993715:
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.
 
B

Brian Candler

7stud -- wrote in post #993798:
Where does this syntax come from?

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

It's invalid in 1.8:
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: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]
 
M

Michael Edgar

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
(e-mail address removed)
http://carboni.ca/
 
A

Adam Prescott

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

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.
 
7

7stud --

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
 
7

7stud --

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
 
S

Stu

[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?

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
 
R

Robert Klemme

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
 
S

Steve Klabnik

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

I would highly reccommend Haskell, and http://learnyouahaskell.com/ .
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
 
B

Brian Candler

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]
$
 
7

7stud --

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.
 
J

Jeremy Bopp

Michael Edgar wrote in post #993817:

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top