Ruby: Renewable Functions with Arguments

I want a function that saves local state in Ruby. Every time I call a function, I want to return a result that depends on both the calling argument and the state of the stored function. Here is a simple example:

def inc_mult(factor)
  @state ||= 0   # initialize the state the first time.
  @state += 1    # adjust the internal state.
  factor * @state
end

Note that the state is initialized for the first time, but subsequent calls access the saved state. This is good, except that it @stateseeps into the surrounding context, which I do not want.

What is the most elegant way to rewrite this so that it @statedoesn't leak out?

(Note: my actual example is much more complex and initializing state is expensive.)

+5
source share
6 answers

, inc_mult , . ( yield) Python #.

- , :

class Foo 
  state = 0 
  define_method(:[]) do |factor|
    state += 1
    factor * state
  end 
end

, , , , Rubys , , .

+4

. . , . - :


Ruby, , , . , :

require 'incmodule'
IncModule::inc_mult(10)

-

+2

, Ruby.

"" , . , , -. , , :

var state;
function incMult(factor) {
    if (state === undefined) {
        state = 0;
    }
    state += 1;
    return factor * state;
}
print(incMult(2)); // => 2
print(incMult(2)); // => 4
print(incMult(2)); // => 6

ECMAScript, .

[. , , ECMAScript - , , , state . ( ECMAScript ), . ECMAScript , .]

, , , , .

1960- , , , , . , , .

, - . , Ruby , . : .

, Ruby :

inc_mult = Object.new
def inc_mult.call(factor)
  @state ||= 0
  @state += 1
  factor * @state
end
p inc_mult.(2) # => 2
p inc_mult.(2) # => 4
p inc_mult.(2) # => 6

[Sidenote: 1:1 - , , , " - ". , - " - ". , , .]

, , , , Ruby , : . (, .) , , , :

foo = Object.new
state = nil
foo.define_singleton_method :inc_mult do |factor|
  state ||= 0
  state += 1
  factor * state
end
p foo.inc_mult(2) # => 2
p foo.inc_mult(2) # => 4
p foo.inc_mult(2) # => 6
+1

It looks like you could just use a global or class variable in some other class, which would at least allow you to skip the context right next to it.

0
source

Well, you can play a little ... How about a function that rewrites itself?

def imult(factor)
  state = 1;
  rewrite_with_state(state+1)
  factor*state
end

def rewrite_with_state(state)
  eval "def imult(factor); state = #{state}; rewrite_with_state(#{state+1}); factor*state; end;"
end

Warning: This is very ugly and should not be used in production code!

0
source

you can use lambda. eg,

$ cat test.rb

def mk_lambda( init = 0 )
  state = init
  ->(factor=1, incr=nil){ 
    state += incr || 1;
    puts "state now is: #{state}"
    factor * state
  }
end

f = mk_lambda

p f[]
p f[1]
p f[2]
p f[100]
p f[100,50]
p f[100]

$ ruby ​​test.rb

state now is: 1
1
state now is: 2
2
state now is: 3
6
state now is: 4
400
state now is: 54
5400
state now is: 55
5500

Regards -botp

0
source

All Articles