简体   繁体   English

可以对instance_eval进行咖喱处理吗?

[英]Possible to instance_eval a curried proc?

Suppose I have a class such as this: 假设我有一个这样的课:

class Test
  def test_func
    140
  end
end

And a proc, which references a member function from Test : 还有一个proc,它引用了Test的成员函数:

p = ->(x, y) { x + y + test_func }  # => #<Proc:0x007fb3143e7f78@(pry):6 (lambda)>

To call p , I bind it to an instance of Test : 要调用p ,我将其绑定到Test一个实例:

test = Test.new                     # => #<Test:0x007fb3143c5a68>
test.instance_exec(1, 2, &p)        # => 143

Now suppose I want to pass just y to p , and always pass x = 1 : 现在假设我只想将y传递给p ,并且始终传递x = 1

curried = p.curry[1]                # => #<Proc:0x007fb3142be070 (lambda)>

Ideally I should be able to just instance_exec as before, but instead: 理想情况下,我应该能够像以前一样只使用instance_exec ,但是:

test.instance_exec(2, &curried)

=> NameError: undefined local variable or method `test_func' for main:Object

The proc runs in what seems to be the incorrect binding. proc运行在似乎是不正确的绑定中。 What gives? 是什么赋予了?

Yes, I believe this is a bug. 是的,我相信这是一个错误。

I think it comes down to the fact that curry returns a "C level proc" rather than a normal proc. 我认为可以归结为以下事实: curry返回“ C level proc”而不是常规proc。 I don't fully understand the difference between the two (I'm guessing the former is one created by the Ruby C code which is what curry does), but you can tell they're different when you try and take a binding. 我不完全理解两者之间的区别(我猜前者是由Ruby C代码创建的,而curry正是这样做的),但是当您尝试进行绑定时,您可以告诉他们它们是不同的。

p.binding # => #<Binding:0x000000020b4238>
curried.binding # => ArgumentError: Can't create a binding from C level Proc

By looking at the source , this looks like their internal struct representations have different values for the iseq member, which says what kind of instruction sequence this block holds. 通过查看源代码 ,看起来它们的内部结构表示形式对于iseq成员而言具有不同的值,该值表示此块持有哪种指令序列。

This is significant when you call instance_exec , which eventually ends up calling invoke_block_from_c in vm.c , which branches depending on the iseq type: 当你调用这是显著instance_exec ,最终结束调用invoke_block_from_cvm.c ,这取决于分支iseq类型:

else if (BUILTIN_TYPE(block->iseq) != T_NODE) {
    ...
} else {
    return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr);
}

The branch I missed out ( ... ) ends up calling vm_push_frame with what looks like some environment where as vm_yield_with_cfunc doesn't. 我错过的分支( ... )最终以类似于vm_yield_with_cfunc没有的环境的方式调用vm_push_frame

So my guess would be that because the curried proc is created in C code and ends up of a different 'type' than your first proc, the other branch is taken in the above snippet and the enviornment isn't used. 因此,我的猜测是,因为咖喱的proc是用C代码创建的,并且结局的类型与您的第一个proc不同,所以上面的代码段采用了另一个分支,并且不使用环境。

I should point out that all of this is pretty speculative based on reading the code, I haven't run any tests or tried anything out (and I'm also not all that familiar with internal Ruby anyway!) 我要指出的是,这一切是相当投机基于阅读的代码,我没有运行任何测试或尝试新鲜事物出来(我也没有那么熟悉内部红宝石反正!)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM