How to make Lambda (or lambda-like object) to call itself with a new parameter it got (Ruby)
Slightly confused, is this what you're trying to achieve? I notice you have variable x
, but this isn't referred anywhere (just answer
is).
lam = ->(x) do
x = Integer(x)
case x
when 1
x * 5
when 2
x * 10
else
puts 'Please enter 1 or 2'
input = gets.chomp
lam.call(input)
end
end
# 2.2.2 > lam.call(5)
# Please enter 1 or 2
# 3
# Please enter 1 or 2
# 2
# => 20
# 2.2.2 > lam.call(1)
# => 5
In Ruby, how can I reference a lambda defined in a module?
try this:
module GalleryGenerator
def self.add_links_to_descriptions
lambda do |mutable_viewable_content|
mutable_viewable_content.description = add_links_to_sources(mutable_viewable_content.description)
return mutable_viewable_content
end
end
#...
end
and call it with GalleryGenerator.add_links_to_descriptions
returning a method reference wrapped in a lambda
Lambdas (and blocks, and procs) in Ruby are closures; this means that local variables available in the same scope as the lambda is defined are accessible inside the lambda. For example:
foo = 42
l = lambda{ p foo }
l.call()
#=> 42
The above should not be any more surprising than the fact that this code works:
x = 17
[1,2,3].map do |n|
n+x # Whoa, you can use _x_ here?!
end
#=> [18,19,20]
It's slightly more surprising when you do something like this:
def make_adder( x )
->(y){ x+y }
end
add10 = make_adder(10)
z = add10.call(32) #=> 42
Again, the local variable x (the parameter passed to the method) is "closed over" by the lambda, its value preserved for reference whenever the lambda is invoked.
So in your example the lambda is just "capturing" the bark_string
variable and returning its value later on. Your method is never invoked a second time.
Note that a closure captures the variable itself, not just the object referred to by the variable:
x = "hello"
y = x # reference the same _object_
l = ->{ x } # close over the _variable_ itself
x = "world" # change the variable to point to a new object
p y, #=> "hello" (same object as the original)
l[] #=> "world" (new object)
Calling a lambda from another lambda. Why does the order matter?
first = -> { defined? second }
second = -> { 'Ok' }
p first.call
results nil => The variable "second" is not defined in the lambda "first".
first = -> { binding.receiver }
second = -> { 'Ok' }
p first.call
results main => This means that it uses the current binding of main and thus the variable "second" is defined only in the binding.
first = -> { binding.local_variable_get(:second).call }
second = -> { 'Ok' }
p first.call
results "Ok". That's why the code also prints "Ok" when I ask for the content of the variable "second" of the binding.
Summary: The variable "second" is not defined in the lambda "first". The variable "second" is only defined in the binding. Therefore, the output of "local_variables" also returns "second" because the information is retrieved from the binding.
I also learned something myself. I hope I could help you!
can you pass self to lambda in rails?
Disclaimer: First, the question (Can you pass self to lambda?) and the problem you're trying to solve (dynamic styles with paperclip) don't fully match up. I won't answer the original question because it's not entirely related to your problem, and rampion took a valiant stab at it.
I'll instead answer your paperclip question.
In detail it is the
has_attached_file
method for the paperclip plugin in rails. I want to pass a lambda for the styles hash so that the image styles can be based off of attributes of the object stored in the DB. Is this possible?
Yes, it is possible. In paperclip, the :styles
option can take a Proc. When the attachment is initialized, if a Proc was used, the attachment itself is passed to the Proc. The attachment has a reference to the associated ActiveRecord object, so you can use that to determine your dynamic styles.
For example, your has_attached_file
declaration might look something like this (assuming a User and avatar scenario where the user can customize the size of their avatar):
class User < ActiveRecord::Base
has_attached_file :avatar, :styles => lambda { |attachment|
user = attachment.instance
dimensions = "#{user.avatar_width}x#{user.avatar_height}#"
{ :custom => dimensions }
}
end
Reference the invoking object in the passed block in Ruby
You can use something similar to Instance eval with delegation pattern, used - for example - in Savon gem:
def batman(task, &block)
@original_self = eval('self', block.binding)
puts "Batman: #{task} - done"
instance_exec('feed cat', &block)
@news << task
end
private
def method_missing(method, *args, &block)
if @original_self
@original_self.send(method, *args, &block)
else
super
end
end
In this approach, when you call method (with implicit receiver) inside block passed into batman
method, it's called in the context of SuperHeros
instance. If there is no such method available, the call goes (through method_missing
) to original block self
.
Where and when to use Lambda?
It's true, you don't need anonymous functions (or lambdas, or whatever you want to call them). But there are a lot of things you don't need. You don't need classes—just pass all the instance variables around to ordinary functions. Then
class Foo
attr_accessor :bar, :baz
def frob(x)
bar = baz*x
end
end
would become
def new_Foo(bar,baz)
[bar,baz]
end
def bar(foo)
foo[0]
end
# Other attribute accessors stripped for brevity's sake
def frob(foo,x)
foo[0] = foo[1]*x
end
Similarly, you don't need any loops except for loop...end
with if
and break
. I could go on and on.1 But you want to program with classes in Ruby. You want to be able to use while
loops, or maybe even array.each { |x| ... }
, and you want to be able to use unless
instead of if not
.
Just like these features, anonymous functions are there to help you express things elegantly, concisely, and sensibly. Being able to write some_function(lambda { |x,y| x + f(y) })
is much nicer than having to write
def temp(x,y)
x + f(y)
end
some_function temp
It's much bulkier to have to break off the flow of code to write out a def
fed function, which then has to be given a useless name, when it's just as clear to write the operation in-line. It's true that there's nowhere you must use a lambda, but there are lots of places I'd much rather use a lambda.
Ruby solves a lot of the lambda-using cases with blocks: all the functions like each
, map
, and open
which can take a block as an argument are basically taking a special-cased anonymous function. array.map { |x| f(x) + g(x) }
is the same as array.map(&lambda { |x| f(x) + g(x) })
(where the &
just makes the lambda "special" in the same way that the bare block is). Again, you could write out a separate def
fed function every time—but why would you want to?
Languages other than Ruby which support that style of programming don't have blocks, but often support a lighter-weight lambda syntax, such as Haskell's \x -> f x + g x
, or C#'s x => f(x) + g(x);
2. Any time I have a function which needs to take some abstract behavior, such as map
, or each
, or on_clicked
, I'm going to be thankful for the ability to pass in a lambda instead of a named function, because it's just that much easier. Eventually, you stop thinking of them as somehow special—they're about as exciting as literal syntax for arrays instead of empty().append(1).append(2).append(3)
. Just another useful part of the language.
1: In the degenerate case, you really only need eight instructions: +-<>[].,
. <>
move an imaginary "pointer" along an array; +-
increment and decrement the integer in the current cell; []
perform a loop-while-non-zero; and .,
do input and output. In fact, you really only need just one instruction, such as subleq a b c
(subtract a
from b
and jump to c
if the result is less than or equal to zero).
2: I've never actually used C#, so if that syntax is wrong, feel free to correct it.
returning a method reference wrapped in a lambda
Lambdas (and blocks, and procs) in Ruby are closures; this means that local variables available in the same scope as the lambda is defined are accessible inside the lambda. For example:
foo = 42
l = lambda{ p foo }
l.call()
#=> 42
The above should not be any more surprising than the fact that this code works:
x = 17
[1,2,3].map do |n|
n+x # Whoa, you can use _x_ here?!
end
#=> [18,19,20]
It's slightly more surprising when you do something like this:
def make_adder( x )
->(y){ x+y }
end
add10 = make_adder(10)
z = add10.call(32) #=> 42
Again, the local variable x (the parameter passed to the method) is "closed over" by the lambda, its value preserved for reference whenever the lambda is invoked.
So in your example the lambda is just "capturing" the bark_string
variable and returning its value later on. Your method is never invoked a second time.
Note that a closure captures the variable itself, not just the object referred to by the variable:
x = "hello"
y = x # reference the same _object_
l = ->{ x } # close over the _variable_ itself
x = "world" # change the variable to point to a new object
p y, #=> "hello" (same object as the original)
l[] #=> "world" (new object)
How to return a lambda that is returned by another method in Ruby
n_times
is a method requiring one argument, you are calling it as the first argument passed to other
, but without an argument. That's the error you are getting. You want to pass method(:n_times)
which converts it to a Proc rather than calling it.
Secondly you have counter(thing)
inside the other
method. This is calling the method called 'counter', rather than using the object called 'counter' which is passed as an argument. You want to change that to counter[thing]
.
Lastly, you are passing 10 to n_times
and calling the resulting lambda with "what", but that evaluates 10 * "what"
which is a NoMethodError. You need to reverse those arguments.
All together:
def n_times(thing)
lambda { |n| thing * n }
end
def other(counter, thing)
counter[thing]
end
other(method(:n_times), "what").call(10)
# "whatwhatwhatwhatwhatwhatwhatwhatwhatwhat"
Related Topics
Ruby Way to Group Anagrams in String Array
How to Install 'Cocoapods' Gem from Rubygems.Org (Bad Response Backend Read Error)
Creating a Hash with Values as Arrays and Default Value as Empty Array
Ruby Equivalent of Perl Data::Dumper
How to Check If There's a Nil Set or Not in an Array
Clarification on the Ruby << Operator
Most Efficient Way to Calculate Hamming Distance in Ruby
Ruby on Rails, Paperclip, Amazon Aws S3 & Heroku
Finding Lines in a Text File Matching a Regular Expression
Including/Extending the Kernel Doesn't Add Those Methods on Main:Object
Get Link and Href Text from HTML Doc with Nokogiri & Ruby
Rake Assets:Precompile Gets Killed When There Is a Console Session Open in Production
Should I Check in '.Ruby-Gemset' And/Or '.Ruby-Version'
Get Title, Content via Link in Rails
Certificate Verify Failed in "Gem Install Foundation"
Convert Array to Hash While Preserving Array Index Values in Ruby