Блоки, лямбды, замыкания

790 views

Published on

Как в Руби внутри устроены блоки, лямбды и замыкания.

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
790
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Блоки, лямбды, замыкания

  1. 1. Лямбды, блоки,замыканияА давайте посмотрим, что уних внутри
  2. 2. Дмитрий Кириенко Twitter: @DimKiriyenko Github: dmitriy- kiriyenko
  3. 3. rb_block_t ???
  4. 4. 10.times do str = "Hello world." puts strendputstring "Hello world." rb_block_tsetlocal str, 0putselfgetlocal str, 0 iseqsend :puts, 1leave
  5. 5. str_ext = "Hello"10.times do str = "world." puts "#{str_ext} #{str}"end
  6. 6. "Чтобы решить эту проблему мы вводимпонятие замыкания как структуры,содержащей лямбда-выражение иокружение, которое будет использовано,когда это выражение будет применено ксвоим аргументам."Scheme: An Interpreter for Extended Lambda Calculus
  7. 7. str_ext = "Hello"10.times do str = "world." puts "#{str_ext} #{str}"end Кадр стека верхнегоВнутренний стек YARV уровня rb_control_frame_t locals: str_ext EP
  8. 8. str_ext = "Hello"10.times do str = "world." puts "#{str_ext} #{str}" rb_block_tend iseq EP Кадр стека верхнегоВнутренний стек YARV уровня rb_control_frame_t locals: str_ext EP
  9. 9. str_ext = "Hello"10.times do str = "world." puts "#{str_ext} #{str}"end Кадр стекаВнутренний стек YARV Fixnum#times rb_control_frame_t EP locals: str_ext
  10. 10. 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
  11. 11. DEFINE_INSNgetlocal(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
  12. 12. "Чтобы решить эту проблему мы вводимпонятие замыкания как структуры,содержащей лямбда-выражение иокружение, которое будет использовано,когда это выражение будет применено ксвоим аргументам."Scheme: An Interpreter for Extended Lambda Calculus
  13. 13. Control frame Blocktypedef structrb_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;
  14. 14. require benchmark while 6763524 in 5.036406srequire benchmark/ips block 4267105 in 5.016071sBenchmark.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} endend
  15. 15. def get_helloer str_ext = "Hello" lambda do |who| puts "#{str_ext} #{who}!" endendhelloer = get_helloerhelloer.call(there)
  16. 16. В 1930-х годах Алонзо Чёрч ввёл лямбда-нотацию в своём исследовании "Лямбда-исчисление"
  17. 17. def get_helloer str_ext = "Hello" lambda do |who| puts "#{str_ext} #{who}!" endendhelloer = get_helloerhelloer.call(there)
  18. 18. rb_lambda_t ???
  19. 19. locals: str_ext rb_control_frame_t Кадр стека get_helloerСтекКуча RString "Hello"
  20. 20. locals: str_ext rb_control_frame_t Кадр стека get_helloerСтекКуча rb_proc_t rb_block_t str_ext iseq rb_env_t EP env envval is_lambda
  21. 21. helloer locals: str_ext rb_control_frame_t Кадр стека внешнего кодаСтекКуча rb_proc_t rb_env_t str_ext
  22. 22. 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
  23. 23. def get_helloer str_ext = "Hello" res = lambda do |who| puts "#{str_ext} #{who}!" end str_ext = "Goodbye" resendhelloer = get_helloerhelloer.call(there)
  24. 24. def get_helloer str_ext = "Hello" res = lambda do |who| puts "#{str_ext} #{who}!" end str_ext = "Goodbye" resendhelloer = get_helloerhelloer.call(there) Goodbye there!
  25. 25. Кадр стека get_helloer locals: str_ext rb_control_frame_t EPСтекКуча str_ext rb_env_t env
  26. 26. def create_counter(start) value = start { inc: ->{value+=1}, dec: ->{value-=1}, get: ->{value} }endcounter = create_counter(500)counter[:inc].callputs counter[:get].call #=> 50110.times { counter[:dec].call }puts counter[:get].call #=> 491 501 491
  27. 27. require benchmark/ips block 19659752 in 5.000587s lambda 4574745 in 5.033561sdef do_with_block yieldenddef do_with_lambda(&block) block.callendBenchmark.ips do |b| b.report block do do_with_block { 1+1 } end b.report lambda do do_with_lambda {1+1} endend
  28. 28. str_ext = "Hello" 10.times do str = "world." puts "#{str_ext} #{str}" end _file_ DynamicScope str_extRubyFixnum.times родитель DynamicScopeblock_0$RUBY$__file__ JRuby
  29. 29. str_ext = "Hello" 10.times do str = "world." puts "#{str_ext} #{str}" endкод верхнего уровня VariableScope str_ext Integer.times родитель VariableScope код блока Rubinius

×