如何在 Ruby 中封送 lambda (Proc)?

发布于 2024-07-04 11:20:35 字数 558 浏览 14 评论 0原文

Joe Van Dyk 询问 Ruby 邮件列表

嗨,

在 Ruby 中,我猜你不能封送 lambda/proc 对象,对吧? 是 这在 Lisp 或其他语言中可能吗?

我想做什么:

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

因此,我向 BackgroundJob 发送一个 lambda 对象,其中包含 做什么的上下文/代码。 但是,我猜这是不可能的。 我 最终整理了一个包含指令的普通 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

GRAY°灰色天空 2024-07-11 11:20:35

如果proc被定义到一个文件中,你可以获取proc的文件位置然后将其序列化,然后在反序列化后使用该位置再次返回到proc

proc_location_array = proc.source_location

文件名 = proc_location_array[0]

行号 = proc_location_array[1]

proc_line_code = IO.readlines(file_name)[line_number - 1]

proc_hash_string = proc_line_code[proc_line_code.index("{")..proc_line_code.length]

proc = eval("lambda #{proc_hash_string}")

If proc is defined into a file, U can get the file location of proc then serialize it, then after deserialize use the location to get back to the proc again

proc_location_array = proc.source_location

after deserialize:

file_name = proc_location_array[0]

line_number = proc_location_array[1]

proc_line_code = IO.readlines(file_name)[line_number - 1]

proc_hash_string = proc_line_code[proc_line_code.index("{")..proc_line_code.length]

proc = eval("lambda #{proc_hash_string}")

醉殇 2024-07-11 11:20:35

我发现 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

I've found proc_to_ast to do the best job: https://github.com/joker1007/proc_to_ast.

Works for sure in ruby 2+, and I've created a PR for ruby 1.9.3+ compatibility(https://github.com/joker1007/proc_to_ast/pull/3)

梦明 2024-07-11 11:20:35

如果您有兴趣使用 Ruby2Ruby 获取 Ruby 代码的字符串版本,您可能会喜欢 此线程

If you're interested in getting a string version of Ruby code using Ruby2Ruby, you might like this thread.

夜司空 2024-07-11 11:20:35

曾几何时,这可以使用 ruby​​-internal gem (https://github.com/cout/ ruby-internal),eg:

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

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

上面的代码适用于 YARV(最高 1.9.3)和 MRI(最高 1.8.7)。 没有理由不让它在 Ruby 2.x 上工作,只需付出少量的努力。

Once upon a time, this was possible using ruby-internal gem (https://github.com/cout/ruby-internal), e.g.:

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

There are some caveats, but it has been many years and I cannot remember the details. As an example, I'm not sure what happens if a variable is a dynvar in the binding where it is dumped and a local in the binding where it is re-bound. Serializing an AST (on MRI) or bytecode (on YARV) is non-trivial.

The above code works on YARV (up to 1.9.3) and MRI (up to 1.8.7). There's no reason why it cannot be made to work on Ruby 2.x, with a small amount of effort.

耳根太软 2024-07-11 11:20:35

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

正如 Gaius 指出的,您可以使用 ruby2ruby 来获取程序的字符串。 也就是说,您可以整理表示 ruby​​ 代码的字符串,然后稍后重新评估它。

You cannot marshal a Lambda or Proc. This is because both of them are considered closures, which means they close around the memory on which they were defined and can reference it. (In order to marshal them you'd have to Marshal all of the memory they could access at the time they were created.)

As Gaius pointed out though, you can use ruby2ruby to get a hold of the string of the program. That is, you can marshal the string that represents the ruby code and then reevaluate it later.

黄昏下泛黄的笔记 2024-07-11 11:20:35

你也可以只输入你的代码作为字符串:

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

然后用 eval 执行它

eval code

,它将返回一个 ruby​​ lamda。

使用 %{} 格式转义字符串,但仅以不匹配的大括号结束。 即您可以像这样嵌套大括号 %{ [] {} } 并且它仍然是封闭的。

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

you could also just enter your code as a string:

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

then execute it with eval

eval code

which will return a ruby lamda.

using the %{} format escapes a string, but only closes on an unmatched brace. i.e. you can nest braces like this %{ [] {} } and it's still enclosed.

most text syntax highlighters don't realize this is a string, so still display regular code highlighting.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文