天道酬勤,学无止境

如何在Ruby中封送lambda(Proc)?(How do I marshal a lambda (Proc) in Ruby?)

问题

Joe Van Dyk询问了Ruby邮件列表:

你好,

在Ruby中,我想您无法编组lambda / proc对象,对吗? 是否可以用lisp或其他语言?

我正在尝试做的是:

l = lamda { ... }
Bj.submit "/path/to/ruby/program", :stdin => Marshal.dump(l)

因此,我正在向BackgroundJob发送一个lambda对象,该对象包含要执行的操作的上下文/代码。 但是,猜测那是不可能的。 我最终整理了一个正常的红宝石对象,其中包含程序运行后的操作说明。

回答1

您无法封送Lambda或Proc。 这是因为它们都被视为闭包,这意味着它们会在定义它们的内存周围关闭并可以引用它。 (要封送它们,您必须封送它们在创建时可以访问的所有内存。)

正如Gaius指出的那样,您可以使用ruby2ruby获取该程序的字符串。 也就是说,您可以封送代表红宝石代码的字符串,然后在以后重新评估它。

回答2

您也可以只将代码作为字符串输入:

code = %{
    lambda {"hello ruby code".split(" ").each{|e| puts e + "!"}}
}

然后用eval执行

eval code

这将返回一个红宝石lamda。

使用%{}格式可对字符串进行转义,但仅在不匹配的花括号上关闭。 也就是说,您可以像这样%{ [] {} }嵌套花括号,并且它仍然是封闭的。

大多数文本语法突出显示程序都没有意识到这是一个字符串,因此仍会显示常规代码突出显示。

回答3

如果您对使用Ruby2Ruby获取Ruby代码的字符串版本感兴趣,则可以使用此线程。

回答4

尝试ruby2ruby

回答5

我发现proc_to_ast做得最好:https://github.com/joker1007/proc_to_ast。

确保可以在ruby 2+中正常工作,并且我已经为ruby 1.9.3+兼容性创建了PR(https://github.com/joker1007/proc_to_ast/pull/3)

回答6

曾几何时,使用ruby-internal gem(https://github.com/cout/ruby-internal)可以做到这一点,例如:

p = proc { 1 + 1 }    #=> #<Proc>
s = Marshal.dump(p)   #=> #<String>
u = Marshal.load(s)   #=> #<UnboundProc>
p2 = u.bind(binding)  #=> #<Proc>
p2.call()             #=> 2

有一些警告,但是已经有很多年了,我不记得细节了。 例如,我不确定如果变量在转储的绑定中是dynvar,而在绑定的本地是重新绑定的本地变量,会发生什么情况。 序列化AST(在MRI上)或字节码(在YARV上)并非易事。

上面的代码适用于YARV(最高1.9.3)和MRI(最高1.8.7)。 没有理由不花一点精力就无法使其在Ruby 2.x上运行。

回答7

如果在文件中定义了proc,则U可以获取proc的文件位置,然后对其进行序列化,然后在反序列化之后使用该位置再次返回proc。

proc_location_array = proc.source_location

反序列化后:

file_name = proc_location_array [0]

line_number = proc_location_array [1]

proc_line_code = IO.readlines(文件名)[行号-1]

proc_hash_string = proc_line_code [proc_line_code.index(“ {”).. proc_line_code.length]

proc = eval(“ lambda#{proc_hash_string}”)

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 您如何对Ruby代码进行字符串化/序列化?(How do you stringize/serialize Ruby code?)
    问题 我希望能够在我的Ruby代码中编写一个lambda / Proc,对其进行序列化,以便可以将其写入磁盘,然后在以后执行该lambda。 有点像... 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不适用于Procs。 我知道Perl有Data :: Dump :: Streamer,在Lisp中这很简单。 但是有没有办法在Ruby中做到这一点? 换句话说,什么是执行save _ for _ later ? 编辑:下面我的答案很好,但是它不会关闭自由变量(如x )并将它们与lambda一起序列化。 所以在我的例子中... x = 40 s = save_for_later { |y| x + y } # => "lambda { |y|\n (x + y)\n}" ...字符串输出不包含x的定义。 是否有一种解决方案可以考虑到这一点,也许可以通过序列化符号表来解决? 您可以在Ruby中访问它吗? 编辑2 :我更新了我的答案以合并序列化局部变量。 这似乎可以接受。 回答1 使用Ruby2Ruby def save_for_later(&block)
  • How do I marshal a lambda (Proc) in Ruby?
    Joe Van Dyk asked the Ruby mailing list: Hi, In Ruby, I guess you can't marshal a lambda/proc object, right? Is that possible in lisp or other languages? What I was trying to do: l = lamda { ... } Bj.submit "/path/to/ruby/program", :stdin => Marshal.dump(l) So, I'm sending BackgroundJob a lambda object, which contains the context/code for what to do. But, guess that wasn't possible. I ended up marshaling a normal ruby object that contained instructions for what to do after the program ran. Joe
  • Ruby中的proc和lambda有什么区别?(What's the difference between a proc and a lambda in Ruby?)
    问题 您什么时候会使用一个而不是另一个? 回答1 一种区别是它们处理参数的方式。 使用proc {}和Proc.new {}创建proc是等效的。 但是,使用lambda {}为您提供了一个过程,可以检查传递给它的参数数量。 来自ri Kernel#lambda : 与Proc.new等效,除了生成的Proc对象检查调用时传递的参数数量。 一个例子: p = Proc.new {|a, b| puts a**2+b**2 } # => #<Proc:0x3c7d28@(irb):1> p.call 1, 2 # => 5 p.call 1 # => NoMethodError: undefined method `**' for nil:NilClass p.call 1, 2, 3 # => 5 l = lambda {|a, b| puts a**2+b**2 } # => #<Proc:0x15016c@(irb):5 (lambda)> l.call 1, 2 # => 5 l.call 1 # => ArgumentError: wrong number of arguments (1 for 2) l.call 1, 2, 3 # => ArgumentError: wrong number of arguments (3 for 2) 此外,正如Ken所指出的那样
  • 何时在Ruby on Rails中使用lambda?(When to use a lambda in Ruby on Rails?)
    问题 什么时候应该使用lambda或proc? 我已经看到它们被描述为匿名函数,但是我很难理解这个概念。 我希望您能在Ruby中使用任何链接或示例,尤其是在Ruby on Rails中。 回答1 http://augustl.com/blog/2008/procs_blocks_and_anonymous_functions/简要介绍了什么是block / procs / lambda,如何使用它们以及它们与其他语言的功能比较。 它肯定回答了您的问题。 请注意,上一节“关于lambdas的说明”提到的一点仅在Ruby 1.8中适用,而在1.9版中已更改-Ruby:Proc.new {'waffles'}与proc {'waffles'} 回答2 我看不出您在Ruby on Rails和Ruby之间有什么区别。 如果您正在编写Ruby on Rails应用程序,那么您正在编写Ruby代码,因此,如果它在Ruby中有用,则在Ruby on Rails中也应有用。 无论如何,这篇文章,《 Ruby中的一些有用的闭包》应该是有帮助的,以及以下内容:http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ 回答3 什么是lambda? 与您的irb一起尝试。 lam =
  • 何时使用lambda,何时使用Proc.new?(When to use lambda, when to use Proc.new?)
    问题 在Ruby 1.8中,一方面proc / lambda与另一方面Proc.new之间存在细微的差异。 这些区别是什么? 您能提供有关如何决定选择哪一个的指导吗? 在Ruby 1.9中,proc和lambda是不同的。 这是怎么回事? 回答1 使用lambda创建的Proc.new和使用Proc.new创建的Proc.new之间的另一个重要但细微的区别是它们如何处理return语句: 在由lambda创建的proc中, return语句仅从proc本身返回在Proc.new创建的proc中, return语句有点令人惊讶:它不仅从proc还从封装proc的方法中返回控制! 这是由lambda创建的proc的return 。 它的行为可能与您预期的一样: def whowouldwin mylambda = lambda {return "Freddy"} mylambda.call # mylambda gets called and returns "Freddy", and execution # continues on the next line return "Jason" end whowouldwin #=> "Jason" 现在,这是一个由Proc.new创建的proc的return执行相同的操作。 您将看到以下其中一种情况,其中Ruby打破了广受赞誉的
  • 在Ruby中更改Proc的绑定(Change the binding of a Proc in Ruby)
    问题 我有以下代码: l = lambda { a } def some_function a = 1 end 我只想通过lambda和一个特殊的作用域来访问a ,该作用域已在示例中的some_function内部定义a已经存在的位置,或者稍后不久就在与该作用域相同的范围内: l = lambda { a } a = 1 l.call 然后,我发现在调用l ,它仍在使用其自己的绑定,而不是调用它的新绑定。 然后我尝试将其用作: l.instance_eval do a = 1 call end 但这也失败了,我无法解释原因,这很奇怪。 我知道解决方案之一是使用eval ,在其中可以特殊绑定并在文本中执行一些代码,但是我真的不想这样使用。 而且,我知道它能够使用全局变量或实例变量。 但是,实际上我的代码在更深的嵌入式环境中,因此,如果不是很必要,我不想破坏完整的部分。 我已经在文档中引用了Proc类,并且发现了一个引用Proc上下文的函数名称binding 。 尽管该函数仅提供一种访问其绑定的方法,但不能更改它,除非使用Binding#eval 。 它也评估文本,这正是我不喜欢做的事情。 现在的问题是,我是否有更好(或更优雅)的方式来实现这一目标? 还是使用eval已经是常规方式? 编辑以回复@Andrew: 好的,这是我在编写词法分析器时遇到的一个问题
  • 为什么显式收益在Proc中有所作为?(Why does explicit return make a difference in a Proc?)
    问题 def foo f = Proc.new { return "return from foo from inside proc" } f.call # control leaves foo here return "return from foo" end def bar b = Proc.new { "return from bar from inside proc" } b.call # control leaves bar here return "return from bar" end puts foo # prints "return from foo from inside proc" puts bar # prints "return from bar" 我认为return关键字在Ruby中是可选的,无论您是否要求,您总是会return ing。 鉴于此,我发现foo和bar具有不同的输出是令人惊讶的,这取决于foo在Proc f包含显式return的事实。 有人知道为什么会这样吗? 回答1 Ruby具有三个构造: 块不是对象,而是由{ ... }或do ... end 。 proc是由Proc.new或proc创建的Proc对象。 lambda是由lambda (或Ruby 1.8中的proc )创建的Proc 。 Ruby具有三个从某事物返回的关键字:
  • 您如何在Ruby中称呼&:运算符? [复制](What do you call the &: operator in Ruby? [duplicate])
    问题 这个问题已经在这里有了答案: 11年前关闭。 可能重复: Ruby / Ruby on Rails和号冒号快捷方式 map(&:name)在Ruby中是什么意思? 我正在阅读Stackoverflow,偶然发现了以下代码 array.map(&:to_i) 好的,很容易看到这段代码的作用,但是我想更多地了解&:构造,这是我之前从未见过的。 不幸的是,我只能想到的不是“ lambda”。 Google告诉我,Ruby中的Lambda语法为->->(x,y){ x * y } 因此,除了调用单个方法之外,谁都知道神秘的&:是什么以及它能做什么? 回答1 这里有一些动人的部分,但是发生的事情是Symbol#to_proc转换。 这是Ruby 1.9及更高版本的一部分,如果使用更高版本的Rails,也可以使用。 首先,在Ruby中, :foo表示“符号foo ”,因此实际上是您要查看的两个单独的运算符,而不是大的&:运算符。 当您说foo.map(&bar) ,您在告诉Ruby,“向foo对象发送一条消息,以调用map方法(带有我已经定义的块bar ”。 如果bar还不是Proc对象,Ruby将尝试使其成为一个对象。 在这里,我们实际上没有传递块,而是传递了称为bar的符号。 因为我们在Symbol上有一个隐式的to_proc转换,所以Ruby会看到并使用它。 原来
  • How do you stringize/serialize Ruby code?
    I want to be able to write a lambda/Proc in my Ruby code, serialize it so that I can write it to disk, and then execute the lambda later. Sort of like... x = 40 f = lambda { |y| x + y } save_for_later(f) Later, in a separate run of the Ruby interpreter, I want to be able to say... f = load_from_before z = f.call(2) z.should == 42 Marshal.dump does not work for Procs. I know Perl has Data::Dump::Streamer, and in Lisp this is trivial. But is there a way to do it in Ruby? In other words, what would be the implementation of save_for_later? Edit: My answer below is nice, but it does not close over
  • 如何并行运行功能?(How to run functions in parallel?)
    问题 我先进行了研究,但找不到我的问题的答案。 我试图在Python中并行运行多个功能。 我有这样的事情: files.py import common #common is a util class that handles all the IO stuff dir1 = 'C:\folder1' dir2 = 'C:\folder2' filename = 'test.txt' addFiles = [25, 5, 15, 35, 45, 25, 5, 15, 35, 45] def func1(): c = common.Common() for i in range(len(addFiles)): c.createFiles(addFiles[i], filename, dir1) c.getFiles(dir1) time.sleep(10) c.removeFiles(addFiles[i], dir1) c.getFiles(dir1) def func2(): c = common.Common() for i in range(len(addFiles)): c.createFiles(addFiles[i], filename, dir2) c.getFiles(dir2) time.sleep(10) c.removeFiles(addFiles[i]
  • Ruby - lambda vs. Proc.new [duplicate]
    This question already has answers here: Closed 9 years ago. Possible Duplicate: What's the difference between a proc and a lambda in Ruby? When run this Ruby code: def func_one proc_new = Proc.new {return "123"} proc_new.call return "456" end def func_two lambda_new = lambda {return "123"} lambda_new.call return "456" end puts "The result of running func_one is " + func_one puts "" puts "The result of running func_two is " + func_two The result that I get is as follows: The result of running func_one is 123 The result of running func_two is 456 As for func_two, where is the the value of the
  • Ruby: convert proc to lambda?
    Is it possible to convert a proc-flavored Proc into a lambda-flavored Proc? Bit surprised that this doesn't work, at least in 1.9.2: my_proc = proc {|x| x} my_lambda = lambda &p my_lambda.lambda? # => false!
  • 如何指定JAXB封送xsd:dateTime时使用的日期格式?(How do you specify the date format used when JAXB marshals xsd:dateTime?)
    问题 当JAXB将日期对象( XMLGregorianCalendar )编组到xsd:dateTime元素中时。 您如何指定生成的XML的格式? 例如:默认数据格式使用毫秒<StartDate>2012-08-21T13:21:58.000Z</StartDate>我需要省略毫秒。 <StartDate>2012-08-21T13:21:58Z</StartDate> 如何指定我要使用的输出格式/日期格式? 我正在使用javax.xml.datatype.DatatypeFactory创建XMLGregorianCalendar对象。 XMLGregorianCalendar xmlCal = datatypeFactory.newXMLGregorianCalendar(cal); 回答1 您可以使用XmlAdapter来定制如何将日期类型写入XML。 package com.example; import java.text.SimpleDateFormat; import java.util.Date; import javax.xml.bind.annotation.adapters.XmlAdapter; public class DateAdapter extends XmlAdapter<String, Date> { private final
  • Change the binding of a Proc in Ruby
    I have this code: l = lambda { a } def some_function a = 1 end I just want to access a by the lambda and a special scope which has defined a already somewhere like inside some_function in the example, or just soon later in the same scope as: l = lambda { a } a = 1 l.call Then I found when calling l, it is still using its own binding but not the new one where it was called. And then I tried to use it as: l.instance_eval do a = 1 call end But this also failed, it is strange that I can't explain why. I know the one of the solution is using eval, in which I could special a binding and executing
  • Ruby块的最佳解释? [关闭](Best explanation of Ruby blocks? [closed])
    问题 关门了。 这个问题是基于意见的。 它当前不接受答案。 想要改善这个问题吗? 更新问题,以便可以通过编辑此帖子以事实和引用的形式回答。 7年前关闭。 改善这个问题 您可以共享的Ruby块的最佳解释是什么? 用法和编写代码可能会花费很多时间? 回答1 我对此回答提供了自己的解释,并做了一些修改: Ruby中的“块”与通用编程术语“代码块”或“代码块”不同。 假装一下以下(无效的)Ruby代码实际上有效: def add10( n ) puts "#{n} + 10 = #{n+10}" end def do_something_with_digits( method ) 1.upto(9) do |i| method(i) end end do_something_with_digits( add10 ) #=> "1 + 10 = 11" #=> "2 + 10 = 12" ... #=> "9 + 10 = 19" 尽管该代码无效,但它的意图(将某些代码传递给某个方法并让该方法运行该代码)可以在Ruby中以多种方式实现。 这些方法之一是“块”。 Ruby中的Block非常非常类似于一种方法:它可以接受一些参数并为其运行代码。 每当您看到foo{ |x,y,z| ... } foo{ |x,y,z| ... }或foo do |x,y,z| ... end foo do |x
  • 在哪里以及如何指定_(下划线)变量?(Where and how is the _ (underscore) variable specified?)
    问题 大多数人都知道_代表IRB作为最后返回值的持有者的特殊含义,但这不是我要问的。 相反,我问的是_ ,在纯旧的Ruby代码中用作变量名称时是_ 。 在这里,它似乎具有特殊的行为,类似于“不在乎变量”(la Prolog)。 以下是一些有用的示例,说明了其独特的行为: lambda { |x, x| 42 } # SyntaxError: duplicated argument name lambda { |_, _| 42 }.call(4, 2) # => 42 lambda { |_, _| 42 }.call(_, _) # NameError: undefined local variable or method `_' lambda { |_| _ + 1 }.call(42) # => 43 lambda { |_, _| _ }.call(4, 2) # 1.8.7: => 2 # 1.9.3: => 4 _ = 42 _ * 100 # => 4200 _, _ = 4, 2; _ # => 2 这些都是直接在Ruby中运行的(添加了puts )而不是IRB,以避免与它的其他功能冲突。 不过,这全都是我自己实验的结果,因为我在任何地方都找不到有关此行为的任何文档(诚然,这不是最容易搜索的内容)。 最终,我很好奇所有这些在内部如何运作,因此我可以更好地准确了解
  • 可以在Ruby中为map(&:method)语法提供参数吗?(Can you supply arguments to the map(&:method) syntax in Ruby?)
    问题 您可能熟悉以下Ruby速记( a是一个数组): a.map(&:method) 例如,在irb中尝试以下操作: >> a=[:a, 'a', 1, 1.0] => [:a, "a", 1, 1.0] >> a.map(&:class) => [Symbol, String, Fixnum, Float] 语法a.map(&:class)是a.map {|x| x.class}的简写。 a.map {|x| x.class} 。 在“ Ruby中的map(&:name)意味着什么?”中阅读有关此语法的更多信息。 通过&:class语法,您将为每个数组元素创建一个方法调用class 。 我的问题是:您可以为方法调用提供参数吗? 如果是这样,怎么办? 例如,如何转换以下语法 a = [1,3,5,7,9] a.map {|x| x + 2} 到&:语法? 我不建议&:语法更好。 我仅对将&:语法与参数一起使用的机制感兴趣。 我假设您知道+是Integer类的方法。 您可以在irb中尝试以下操作: >> a=1 => 1 >> a+(1) => 2 >> a.send(:+, 1) => 2 回答1 您可以在Symbol上创建一个简单的补丁,如下所示: class Symbol def with(*args, &block) ->(caller, *rest) { caller
  • 如何在Ruby中创建充当False的对象(How to create an Object who act as a False in Ruby)
    问题 我想做这个 lol = Klass.new(values) unless lol print "false" end lol.other_method # it is not nil or false, it is a Klass instance! 但是,在这种情况下,哈哈不是nil或false,而是可以基于某些内部值充当false的对象。 我有这个选择 lol = Klass.new(values) unless lol.to_bool print "false" end 但这是丑陋的恕我直言。 我在考虑扩展FalseClass或玩==,但没有成功。 有任何想法吗? 回答1 不幸的是,这是不可能的。 这是Ruby不是面向对象的烦人情况之一。 在OO中,必须有可能模拟一个对象(实际上,这取决于OO,这是OO的定义-记住OO是出于模拟而产生的),但是不可能建立一个对象来模拟。模拟false 。 这是因为,在Ruby中,条件控制结构被烤成语言,并没有转化为消息发送,而在其他面向对象的语言,他们只是普通的消息发送(或者至少转化为消息发送,就像for Ruby的转换进入each )。 例如,在Smalltalk中,布尔实际上是使用从Lambda微积分中得知的布尔的Church编码实现的,然后转换为Ruby,它们看起来像这样: class FalseClass def if(
  • When to use lambda, when to use Proc.new?
    In Ruby 1.8, there are subtle differences between proc/lambda on the one hand, and Proc.new on the other. What are those differences? Can you give guidelines on how to decide which one to choose? In Ruby 1.9, proc and lambda are different. What's the deal?
  • 在Ruby块中使用“返回”(Using 'return' in a Ruby block)
    问题 我正在尝试将Ruby 1.9.1用于嵌入式脚本语言,以便将“最终用户”代码写入Ruby块中。 与此相关的一个问题是,我希望用户能够在块中使用'return'关键字,因此他们不必担心隐式的返回值。 考虑到这一点,这是我想做的事情: def thing(*args, &block) value = block.call puts "value=#{value}" end thing { return 6 * 7 } 如果在上面的示例中使用“ return”,则会收到LocalJumpError。 我知道这是因为所讨论的块是Proc而不是lambda。 如果删除“ return”,该代码将起作用,但在这种情况下,我真的更希望能够使用“ return”。 这可能吗? 我尝试将块转换为lambda,但结果是相同的。 回答1 在这种情况next ,只需使用next : $ irb irb(main):001:0> def thing(*args, &block) irb(main):002:1> value = block.call irb(main):003:1> puts "value=#{value}" irb(main):004:1> end => nil irb(main):005:0> irb(main):006:0* thing { irb(main):007:1*