7. "Чтобы решить эту проблему мы вводим
понятие замыкания как структуры,
содержащей лямбда-выражение и
окружение, которое будет использовано,
когда это выражение будет применено к
своим аргументам."
Scheme: An Interpreter for Extended Lambda Calculus
8. str_ext = "Hello"
10.times do
str = "world."
puts "#{str_ext} #{str}"
end
Кадр стека верхнего
Внутренний стек YARV уровня
rb_control_frame_t
locals: str_ext EP
9. str_ext = "Hello"
10.times do
str = "world."
puts "#{str_ext} #{str}" rb_block_t
end
iseq
EP
Кадр стека верхнего
Внутренний стек YARV уровня
rb_control_frame_t
locals: str_ext EP
10. str_ext = "Hello"
10.times do
str = "world."
puts "#{str_ext} #{str}"
end
Кадр стека
Внутренний стек YARV Fixnum#times
rb_control_frame_t
EP
locals: str_ext
11. str_ext = "Hello"
10.times do
str = "world."
puts "#{str_ext} #{str}"
end
Кадр стека
Внутренний стек YARV Block#yield
rb_control_frame_t
locals: str
EP
EP
rb_block_t
locals: str_ext iseq
EP
12. DEFINE_INSN
getlocal
(lindex_t idx, rb_num_t level)
()
(VALUE val)
{
int i, lev = (int)level;
VALUE *ep = GET_EP();
for (i = 0; i < lev; i++) {
ep = GET_PREV_EP(ep);
}
val = *(ep - idx);
}
https://github.com/ruby/ruby/blob/trunk/insns.def#L43L67
13. "Чтобы решить эту проблему мы вводим
понятие замыкания как структуры,
содержащей лямбда-выражение и
окружение, которое будет использовано,
когда это выражение будет применено к
своим аргументам."
Scheme: An Interpreter for Extended Lambda Calculus
14. Control frame Block
typedef struct
rb_control_frame_struct {
VALUE *pc;
VALUE *sp;
rb_iseq_t *iseq;
typedef struct
VALUE flag;
rb_block_struct {
VALUE self;
VALUE self;
VALUE klass;
VALUE klass
VALUE *ep;
VALUE *ep;
rb_iseq_t *block_iseq;
rb_iseq_t *iseq;
VALUE proc;
VALUE proc;
const rb_method_entry_t
} rb_block_t;
*me;
#if VM_DEBUG_BP_CHECK
VALUE *bp_check;
#endif
} rb_control_frame_t;
15. require 'benchmark' while 6763524 in 5.036406s
require 'benchmark/ips'
block 4267105 in 5.016071s
Benchmark.ips do |b| reduce 3606540 in 5.054937s
b.report 'while' do
sum = 0; i = 0
while i <= 10
sum += i; i += 1
end
end
b.report 'block' do
sum = 0
(1..10).each do |i|
sum += 1
end
end
b.report 'reduce' do
(1..10).reduce {|acc, i| acc+i}
end
end
16. def get_helloer
str_ext = "Hello"
lambda do |who|
puts "#{str_ext} #{who}!"
end
end
helloer = get_helloer
helloer.call('there')
17. В 1930-х годах Алонзо Чёрч ввёл лямбда-нотацию в своём исследовании
"Лямбда-исчисление"
18. def get_helloer
str_ext = "Hello"
lambda do |who|
puts "#{str_ext} #{who}!"
end
end
helloer = get_helloer
helloer.call('there')
23. argument: who
locals: str_ext
EP
rb_control_frame_t
Кадр стека helloer.
call
Стек
Куча rb_proc_t
rb_block_t
str_ext iseq
rb_env_t EP
env envval
is_lambda
24. def get_helloer
str_ext = "Hello"
res = lambda do |who|
puts "#{str_ext} #{who}!"
end
str_ext = "Goodbye"
res
end
helloer = get_helloer
helloer.call('there')
25. def get_helloer
str_ext = "Hello"
res = lambda do |who|
puts "#{str_ext} #{who}!"
end
str_ext = "Goodbye"
res
end
helloer = get_helloer
helloer.call('there')
Goodbye there!
28. require 'benchmark/ips'
block 19659752 in 5.000587s
lambda 4574745 in 5.033561s
def do_with_block
yield
end
def do_with_lambda(&block)
block.call
end
Benchmark.ips do |b|
b.report 'block' do
do_with_block { 1+1 }
end
b.report 'lambda' do
do_with_lambda {1+1}
end
end
30. str_ext = "Hello"
10.times do
str = "world."
puts "#{str_ext} #{str}"
end
код верхнего уровня VariableScope
str_ext
Integer.times
родитель
VariableScope
код блока
Rubinius