How to do lazy evaluation of Ruby arguments
I have a code to do a check of nil in ruby. So what I want to achieve开发者_如何学运维 is this:
for example, if I call get_score_value(nil,(nil-1))
. I want ruby to delay the evaluation of nil-1
till it reaches the get_score_value
function, instead of evaluate it before it got passed in the function. In another word, I want to pass a mathematical expression as an argument into a method.
What is the most elegant way to do this in ruby? Thanks very much
def get_score_value(value,value2)
value.nil? ? "NULL" : value2.round(2)
end
UPDATE:
I just realized this question is actually related to the topic of lazy and strict evaluation. ( the following is from this great site: http://www.khelll.com/blog/ruby/ruby-and-functional-programming/
Strict versus lazy evaluation
Strict evaluation always fully evaluates function arguments before invoking the function. Lazy evaluation does not evaluate function arguments unless their values are required to be evaluated. One use of Lazy evaluation is the performance increases due to avoiding unnecessary calculations.
However as the following example shows, Ruby use Strict evaluation strategy:
print length([2+1, 3*2, 1/0, 5-4]) =>ZeroDivisionError: divided by 0
The third parameter of the passed array contains a division by zero operation and as Ruby is doing strict evaluation, the above snippet of code will raise an exception.
You might be interested in using a Proc...
func = Proc.new {|n| n -1 }
def get_score_value(value, proc)
if value.nil?
return proc.call(0)
end
end
p get_score_value(nil, func)
Your proc is like a normal method, it can still test for nil and things like that.
Or, it allows you to provide separate functions to handle those situations:
func1 = Proc.new {|n| n -1 }
func2 = Proc.new { "was nil" }
def check_for_nil(value, funcNil, funcNotNil)
if value.nil?
return funcNil.call()
else
return funcNotNil.call(value)
end
end
p check_for_nil(nil, func2, func1)
p check_for_nil(1, func2, func1)
Also note the potential use of the or
keyword in cases when you simply want to convert it to an empty or default type of the input (i.e. use 0 for numbers, [] for arrays, etc.)
def get_score_value(value)
(value or 0).round(2)
end
The Ruby-ish way to do this is to put your expression in your method's block and have the method execute a conditional yield.
def f x
yield if x
end
x = nil
f x do
x - 1
end
You can use a block:
def get_score_value value
value.nil? ? "NULL" : yield
end
x = 1
puts get_score_value(x) { x-1 } #=> 0
x = nil
puts get_score_value(x) { x-1 } #=> "NULL"
精彩评论