代码之家  ›  专栏  ›  技术社区  ›  Peter

Ruby:带参数的可恢复函数

  •  5
  • Peter  · 技术社区  · 15 年前

    我想要一个在Ruby中保持本地状态的函数。每次调用函数时,我都希望返回一个既依赖于调用参数又依赖于函数存储状态的结果。下面是一个简单的例子:

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

    请注意,状态是第一次初始化的,但随后的调用将访问存储状态。这很好,只是 @state 泄露到周围的环境中,我不想。

    最优雅的重写方式是什么 @州

    (注:我的实际例子要多得多。) 复杂,初始化 国家是昂贵的。)

    6 回复  |  直到 15 年前
        1
  •  4
  •   Josh Lee ZZ Coder    15 年前

    inc_mult yield 语句)使用Python和C#。

    就这么简单:

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

    从哲学上讲,我认为你的目标与Rubys的观点是不相容的,Rubys认为方法是消息,而不是可以独立的函数。

        2
  •  2
  •   Mike Trpcic    15 年前

    等级 保持状态
    功能 操纵状态

    因为您使用的是Ruby,所以将这些东西放在一个可以包含的模块中对您来说可能更为简单。模块可以处理维护状态,方法可以通过以下方式调用:

    require 'incmodule'
    IncModule::inc_mult(10)
    

        3
  •  1
  •   Jörg W Mittag    15 年前

    我想要一个 功能 这让当地的政府保持了活力。

    “函数”这个词应该会立即出现一个巨大的红色闪烁警告标志,表明您使用了错误的编程语言。如果需要函数,应该使用函数式编程语言,而不是面向对象的语言。在函数式编程语言中,函数通常关闭在它们的词法环境中,这使得您试图做的事情变得非常琐碎:

    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实际上也是一种面向对象的语言,而且它打破了通常意义上的作用域语义 state 在这种情况下也有泄漏。在具有适当范围语义的语言中(几年后,ECMAScript将是其中之一),这将按预期工作。我使用ECMAScript主要是因为它熟悉的语法,而不是作为一个好的函数式语言的例子。]

    这就是用函数语言封装状态的方式,因为有函数语言,一直到lambda演算。

    所以 对象

    因此,在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
    

    [旁注:这1:1的对应关系正是函数式程序员所说的“对象只是穷人的闭包”。当然,面向对象的程序员通常会用“闭包只是穷人的对象”来反驳。有趣的是,他们两个都是对的,但他们都没有意识到这一点。]

    :块(有趣的是,块不是对象。)而且,由于可以使用块定义方法,因此还可以定义作为闭包的方法:

    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
    
        4
  •  0
  •   DigitalRoss    15 年前

    似乎您可以在其他类中使用全局变量或类变量,这至少允许您跳过周围的上下文。

        5
  •  0
  •   John Topley    15 年前

    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
    

    警告:这是非常丑陋的,不应该在生产代码中使用!

        6
  •  0
  •   botp    11 年前

    $cat测试.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]
    

    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
    

    谨致问候-博普