Блоки, лямбды, замыкания
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

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

  • 856 views
Uploaded on

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

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

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
856
On Slideshare
854
From Embeds
2
Number of Embeds
1

Actions

Shares
Downloads
3
Comments
0
Likes
0

Embeds 2

http://www.hanrss.com 2

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Лямбды, блоки,замыканияА давайте посмотрим, что уних внутри
  • 2. Дмитрий Кириенко Twitter: @DimKiriyenko Github: dmitriy- kiriyenko
  • 3. rb_block_t ???
  • 4. 10.times do str = "Hello world." puts strendputstring "Hello world." rb_block_tsetlocal str, 0putselfgetlocal str, 0 iseqsend :puts, 1leave
  • 5. str_ext = "Hello"10.times do str = "world." puts "#{str_ext} #{str}"end
  • 6. "Чтобы решить эту проблему мы вводимпонятие замыкания как структуры,содержащей лямбда-выражение иокружение, которое будет использовано,когда это выражение будет применено ксвоим аргументам."Scheme: An Interpreter for Extended Lambda Calculus
  • 7. str_ext = "Hello"10.times do str = "world." puts "#{str_ext} #{str}"end Кадр стека верхнегоВнутренний стек YARV уровня rb_control_frame_t locals: str_ext EP
  • 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. 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. 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. 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. "Чтобы решить эту проблему мы вводимпонятие замыкания как структуры,содержащей лямбда-выражение иокружение, которое будет использовано,когда это выражение будет применено ксвоим аргументам."Scheme: An Interpreter for Extended Lambda Calculus
  • 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. 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. def get_helloer str_ext = "Hello" lambda do |who| puts "#{str_ext} #{who}!" endendhelloer = get_helloerhelloer.call(there)
  • 16. В 1930-х годах Алонзо Чёрч ввёл лямбда-нотацию в своём исследовании "Лямбда-исчисление"
  • 17. def get_helloer str_ext = "Hello" lambda do |who| puts "#{str_ext} #{who}!" endendhelloer = get_helloerhelloer.call(there)
  • 18. rb_lambda_t ???
  • 19. locals: str_ext rb_control_frame_t Кадр стека get_helloerСтекКуча RString "Hello"
  • 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. helloer locals: str_ext rb_control_frame_t Кадр стека внешнего кодаСтекКуча rb_proc_t rb_env_t str_ext
  • 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. def get_helloer str_ext = "Hello" res = lambda do |who| puts "#{str_ext} #{who}!" end str_ext = "Goodbye" resendhelloer = get_helloerhelloer.call(there)
  • 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. Кадр стека get_helloer locals: str_ext rb_control_frame_t EPСтекКуча str_ext rb_env_t env
  • 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. 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. str_ext = "Hello" 10.times do str = "world." puts "#{str_ext} #{str}" end _file_ DynamicScope str_extRubyFixnum.times родитель DynamicScopeblock_0$RUBY$__file__ JRuby
  • 29. str_ext = "Hello" 10.times do str = "world." puts "#{str_ext} #{str}" endкод верхнего уровня VariableScope str_ext Integer.times родитель VariableScope код блока Rubinius