Scheme Interpreter in Ruby

Scheme Interpreter in Ruby

社内LT大会 0x64物語 #04 Compiler / Interpreter 資料

3f1b3c7b051241022d973fff2e713c1b?s=128

HORINOUCHI Masato

January 26, 2016
Tweet

Transcript

  1. Scheme Interpreter in Ruby 2016/01/26 0x64 Tales #04 Compiler /

    Interpreter Livesense Inc. HORINOUCHI Masato
  2. ϋοΧʔʹͳΖ͏ LISP ͸ɺͦΕΛϞϊʹͨ͠ͱ͖ͷ͢͹Β͍͠ޛΓମݧͷͨΊʹษ ڧ͠·͠ΐ͏ɻ͜ͷମݧ͸ɺͦͷޙͷਓੜͰΑΓΑ͍ϓϩάϥϚ ʔͱͳΔखॿ͚ͱͳΔ͸ͣͰ͢ɻͨͱ͑ɺ࣮ࡍʹ͸ LISP ͦͷ΋ͷ Λ͋·Γ࢖Θͳͯ͘΋ɻ — Eric

    S. Raymond ϋοΧʔʹͳΖ͏ (How To Become A Hacker) ͔ΒҾ༻
  3. ී௨ͷ΍ͭΒͷ্Λߦ͚ ൴͕Lispʹ͍ͭͯݴ͍ͬͯΔ͜ͱ͸Α͋͘Δҙݟͩɻͭ·ΓɺLisp Λֶ΂͹Α͍ϓϩάϥϚʔʹͳΕΔɺͰ΋ͦΕΛ࣮ࡍʹ࢖͏͜ͱ ͸ͳ͍ɺͱɻ Կނ͍ͩ? ϓϩάϥϛϯάݴޠͳΜͯͨͩͷಓ۩͡Όͳ͍͔ɻLisp Ͱྑ͍ϓϩάϥϜ͕ ॻ͚ΔͳΒɺ࢖͏΂͖ͳΜͩɻ — Paul

    Graham ී௨ͷ΍ͭΒͷ্Λߦ͚ Bea%ng the Averages ͔ΒҾ༻
  4. Let's Talk Lisp ๭Πϕϯτͷೋ࣍ձͰʮ࣮͸RubyͬͯʰMatzLispʱͱ͍͏Lispͷ ํݴͩͬͨΜͩΑʂʯͱޠΒΕͨΑ͏Ͱ͢ɻԿͱ΋ܼ࡞ͳωλͰ ͕͢ɺLispͷڧ͞Λ௧ײͨ͠Θ͕ͨ͠ʮࣗ෼͕ຬ଍͢ΔͨΊʹʯ ࡞Γग़ͨ͠Ruby͸ɺจ๏ͦ͜ҧ͏΋ͷͷɺͦͷຊ࣭ͱͯ͠Lispจ ԽΛܧঝ͍ͯ͠Δͷ͔΋͠Ε·ͤΜɻ — ·ͭ΋ͱΏ͖ͻΖ

    Let's Talk Lisp ͔ΒҾ༻
  5. ࢀߟਤॻ ֶͭͬͯ͘Ϳϓϩάϥϛϯάݴޠ Rubyʹ ΑΔSchemeॲཧܥͷ࣮૷ 1 ϓϩάϥϛϯάΛΑΓਂ͘ཧղ͢ΔͨΊ ͷۙಓ͸ɺϓϩάϥϛϯάݴޠΛ࣮૷͠ ͯΈΔ͜ͱɻSchemeͷαϒηοτΛRuby Ͱ࣮૷͍ͯ͘͜͠ͱͰɺϓϩάϥϜ͸Ͳ ͏࣮ߦ͞ΕΔͷ͔ɺͦͷجຊ͕͸͖ͬΓ

    ෼͔Γ·͢ɻ 1 CC BY ͳͷͰແঈͩΑɻ༗ঈ൛΋͋ΔͷͰྑ͔ͬͨΒങͬͯͶɻ
  6. σϞ

  7. Fibonacci number (Scheme) (define (fib n) (cond ((= n 0)

    0) ((= n 1) 1) (else (+ (fib (- n 2)) (fib (- n 1))))))
  8. Fibonacci number (Ruby) def fib(n) case n when 0 0

    when 1 1 else fib(n-2) + fib(n-1) end end
  9. What is Environments.

  10. ΋͠ಈతείʔϓͩͱͨ͠Β… ((lambda (x) ((lambda (fun) ((lambda (x) (fun)) 1)) (lambda

    () x))) 2) # => 1 ↑ಈతείʔϓͷ Emacs Lisp Ͱ͸্هͷίʔυͰ 1 ͕ฦΓ·͢ɻ
  11. ΋͠(ུ) (Ruby൛) (lambda { |x| (lambda { |fun| (lambda {

    |x| fun.call }).call(1) }).call(lambda { x }) }).call(2) ͪͳΈʹ Ruby ͸੩తείʔϓͳͷͰɺ͋͘·ͰίʔυͷΘ͔Γ ΍͢͞ͷ࿩ɻ Scheme ͱ͋·ΓมΘΒͳ͍ͷ͸ώϛπ…ɻ
  12. ΋͠(ུ) (y ʹมߋ) ((lambda (x) ((lambda (fun) ((lambda (y) (fun))

    1)) (lambda () x))) 2) # => 2 ↑಺ଆͷ (x) Λ (y) ʹม਺໊มߋ͚ͨͩ͠Ͱ 2 ʹͳΔɻ
  13. ΋͠੩తείʔϓͩͱͨ͠Β… ((lambda (x) ((lambda (fun) ((lambda (x) (fun)) 1)) (lambda

    () x))) 2) # => 2 ↑ y ʹมߋͱಉ༷ 2 ʹͳΔɻ
  14. ؀ڥϞσϧ • ֎ଆͷ lambda x ͱ಺ଆͷ lambda x Λ۠ผ͢Δඞཁ͕͋Δɻ •

    ֎ଆͷ lambda ΛධՁ͍ͯ͠Δͱ͖͸ {x: 2} ͱ͢Δɻ • ಺ଆͷ lambda ΛධՁ͍ͯ͠Δͱ͖͸ {x: 1} ͱ͢Δɻ • ਅΜதͷ lambda fun ΛධՁͨ͠ࡍʹɺλࣜͱධՁ࣌ͷ؀ڥΛϖ Ξͱͯ͠ΫϩʔδϟʔΛฦ͢ɻ
  15. closure • Ϋϩʔδϟʔ͸λࣜͱ؀ڥͷϖΞɻ • λࣜΛධՁ͢ΔͱΫϩʔδϟʔ͕ධՁ஋ͱͳΔɻ • ΫϩδϟʔΛؔ਺ద༻͢Δͱ͖͸ɺΫϩʔδϟʔதͷ؀ڥΛ༻ ͍ͯධՁ͢Δɻ => ؀ڥ(੩తείʔϓ)͕ͳ͍ͱ

    closure ͸࡞Εͳ͍ɻ
  16. ධՁͱؔ਺ద༻ • ؔ਺ͱҾ਺ͷ෦෼ʹ෼͚ɺͦΕͧΕΛධՁ͢Δɻ • Ҿ਺Λͦͷؔ਺ʹద༻͢Δɻ • ؔ਺ͷԾҾ਺ʹ࣮Ҿ਺Λଋറ͠ɺؔ਺ͷϘσΟΛධՁ͢Δɻ => ධՁ(eval)ͱؔ਺ద༻(apply)Λ࠶ؼతʹ܁Γฦ͢ɻ

  17. ࣮૷ • Ruby ͷ _eval ؔ਺ͱ apply ؔ਺Λ࣮ߦ͍ͯ͘͠ • Scheme

    ͷϦετ͸ Ruby ͷ Array • Scheme ͷ؀ڥ͸ Ruby ͷ Hash ͷ Array • Scheme ͸ Lisp-1 ͳͷͰɺHash ͷ Array ͸1͚ͭͩͰ okܥɻ
  18. _eval def _eval(exp, env) if not list?(exp) if immediate_val?(exp) exp

    else lookup_var(exp, env) end else if special_form?(exp) eval_special_form(exp, env) else fun = _eval(car(exp), env) args = eval_list(cdr(exp), env) apply(fun, args) end end end
  19. apply def apply(fun, args) if primitive_fun?(fun) apply_primitive_fun(fun, args) else lambda_apply(fun,

    args) end end
  20. lookup_var ͱ extend_env def lookup_var(var, env) alist = env.find {

    |alist| alist.key?(var) } if alist == nil raise "couldn't find value to variables: '#{var}'" end alist[var] end def extend_env(parameters, args, env) alist = parameters.zip(args) h = Hash.new alist.each { |k, v| h[k] = v } [h] + env # ↑ ্هͰ env.find ͯ͠ΔͷͰ Array ͷઌ಄ʹ௥Ճ͢Δͷ͕ॏཁɻ end
  21. parse def parse(exp) program = exp.strip(). gsub(/[a-zA-Z\+\-\*><=][0-9a-zA-Z\+\-=!*]*/, ':\\0'). gsub(/\s+/, ',

    '). gsub(/\(/, '['). gsub(/\)/, ']') eval(program) end ↑࠷ޙʹ Ruby ͷ eval ͯ͠Δɻ
  22. Next Step ܭࢉػϓϩάϥϜͷߏ଄ͱղऍ (௨শ SICP) MITͷೖ໳ίʔεͰ࢖͏ܭࢉػՊֶͷ༏ ΕͨڭՊॻ ϋϧɾΤΠϒϧιϯ, δΣϦ ʔɾαεϚϯ,

    δϡϦʔɾαεϚϯڞஶ(࿨ ాӳҰ༁)ʮܭࢉػϓϩάϥϜͷߏ଄ͱղ ऍ ୈೋ൛ʯ(ϐΞιϯɾΤσϡέʔγϣϯ 2000೥). දࢴͷຐज़ࢣΏ͑ʹͦ͏͍ΘΕ Δ. LISP/Schemeੈքͷ੟యͷͻͱͭ. ← ਤʹ "Eval / Apply" ͷଠۃਤ (Tao) ͕ඳ ͔Ε͍ͯΔͷʹ͝஫໨ɻ
  23. ·ͱΊ • LISP ͸ߏจղੳ͕ඞཁͳ͍͔Βॲཧܥ࡞Γ΍͍͢ɻ • ؀ڥϞσϧʹΑͬͯ੩తείʔϓΛ࣮ݱ͍ͯ͠Δɻ • Scheme ͸׬શͳ੩తείʔϓͷΫϩʔδϟΛ࣋ͭ࠷ॳͷݴޠ ͱͯ͠ొ৔ͨ͠ɻ

    • Scheme ͸Ғେɻ
  24. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠