我希望能够写入的λ/ PROC在我的Ruby代码,序列化,这样我可以将其写入到磁盘,再后来执行拉姆达。有点像...

x = 40
f = lambda { |y| x + y }
save_for_later(f)

后来,在Ruby解释器的一个独立的运行,我想能够说......

f = load_from_before
z = f.call(2)
z.should == 42

Marshal.dump不适用于特效工作。我知道Perl有数据::转储::流光和Lisp中,这是微不足道的。但是,有没有办法做到这一点的红宝石?换句话说,这将是save_for_later执行?

修改我的答案下面是好的,但它不会关闭在自由变量(如x),并与序列化拉姆达他们一起。所以在我的例子...

x = 40
s = save_for_later { |y| x + y }
# => "lambda { |y|\n  (x + y)\n}"

...字符串输出不包括用于x的定义。有没有通过序列的符号表考虑到了这,也许是一个解决方案吗?您可以访问在Ruby中?

修改2 :我更新了我的答案,包括序列化的局部变量。这似乎可以接受的。

有帮助吗?

解决方案

使用Ruby2Ruby

def save_for_later(&block)
  return nil unless block_given?

  c = Class.new
  c.class_eval do
    define_method :serializable, &block
  end
  s = Ruby2Ruby.translate(c, :serializable)
  s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1|').sub(/end$/, '}')
end

x = 40
s = save_for_later { |y| x + y }
# => "lambda { |y|\n  (x + y)\n}"
g = eval(s)
# => #<Proc:0x4037bb2c@(eval):1>
g.call(2) 
# => 42

这是伟大的,但它并没有关闭了自由变量(如x),并用拉姆达一起序列化。

序列变量另外,还可以遍历local_variables和序列化他们。问题,虽然是从内local_variables只访问save_for_later和在上面的代码cs - 即局部变量的序列化代码,而不是调用者。所以,不幸的是,我们必须推动局部变量的抓取和它们的值给调用者。

也许这是一件好事,但因为一般来说,在一块Ruby代码查找所有自由变量是的不可判定。另外,最好我们也将节省global_variables和任何加载的类及其覆盖的方法。这似乎是不切实际的。

使用这种简单的方法,你会得到如下:

def save_for_later(local_vars, &block)
  return nil unless block_given?

  c = Class.new
  c.class_eval do
    define_method :serializable, &block
  end
  s = Ruby2Ruby.translate(c, :serializable)
  locals = local_vars.map { |var,val| "#{var} = #{val.inspect}; " }.join
  s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1| ' + locals).sub(/end$/, '}')
end

x = 40
s = save_for_later(local_variables.map{ |v| [v,eval(v)] }) { |y| x + y }
# => "lambda { |y| _ = 40; x = 40;\n  (x + y)\n}"

# In a separate run of Ruby, where x is not defined...
g = eval("lambda { |y| _ = 40; x = 40;\n  (x + y)\n}")
# => #<Proc:0xb7cfe9c0@(eval):1>
g.call(2)
# => 42

# Changing x does not affect it.
x = 7
g.call(3)
# => 43

其他提示

使用 sourcify

这将在红宝石1.8或1.9工作。

def save_for_later(&block)
  block.to_source
end

x = 40
s = save_for_later {|y| x + y }
# => "proc { |y| (x + y) }"
g = eval(s)
# => #<Proc:0x00000100e88450@(eval):1>
g.call(2) 
# => 42

请参阅我对方的回答捕捉免费变量

<强>更新: 现在,您也可以使用 serializable_proc 宝石,它采用sourcify,并捕获的地方,例如,阶级,全局变量。

查看答案这个问题

Ruby有具有您可以调用一个方法转储Marshal类。

看看这里:

http://rubylearning.com/satishtalim/object_serialization.html

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top