Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruboty and SKI

7bc6612fa20296bf652f6b0357db81c1?s=47 pocke
January 31, 2020

Ruboty and SKI

7bc6612fa20296bf652f6b0357db81c1?s=128

pocke

January 31, 2020
Tweet

Transcript

  1. Ruboty and SKI Meguro.rb #30 2020-01-31 Fri.

  2. pp self • Masataka “pocke” Kuwabara • Work for BIt

    Journey, Inc. • Live in ruby-jp.slack.com
  3. Agenda • I implemented SKI combinator calculus with Ruboty, so

    I’ll describe the implemetation ◦ What’s Ruboty ◦ What’s SKI combinator calculus ◦ How implement SKI combinator calculus in Ruboty
  4. What’s Ruboty

  5. Ruboty • A chat bot framework written in Ruby •

    https://github.com/r7kamura/ruboty • Customizable by plugins written in Ruby • Ruboty lives in ruby-jp.slack.com ◦ Join us from https://ruby-jp.github.io/! ◦ It is developed in https://github.com/pocke/ruboty-ruby-jp.
  6. Ruboty example

  7. What’s SKI combinator calculus

  8. I’m not sure!!! • I’m not familiar with it •

    But, I’ll try to describe it! • Please give me advices if I’m wrong
  9. SKI combinator calculus • A programming language (maybe) • The

    program examples: ◦ Ix, Kxy, Sxyz ◦ S(K(SI))Kxy • It replaces itself with 3 rules ◦ The rules are S, K and I • I’ll describe rule with reversed order • It manipulates a string in this slide, but actually it manipulates a tree in general
  10. Rule I • “I” takes one argument and returns it

    • In other words, it’s just removed • For example: ◦ Ix => x ◦ Iy => y ◦ IIx => Ix => x ◦ Ixyz => xyz ◦ I(xyz) => xyz
  11. Rule K • “K” takes two arguments and returns the

    first one • For example: ◦ Kxy => x ◦ K(xyz)(abc) => xyz ◦ Kixy => iy => y
  12. Rule S • It takes three arguments, and returns “first

    third(second third)” • For example: ◦ Sxyz => xz(yz) ◦ S(K(SI))Kxy => K(SI)x(Kx)y => SI(Kx)y => Iy(Kxy) => y(Kxy) => yx
  13. How implement SKI combinator calculus in Ruboty

  14. The easiest way: Create a plugin • We can create

    a plugin with writing the algorithm in Ruby • But it is not interesting! It is too easy! • So, I went to more difficult way
  15. More difficult way: Combination of plugins • We can combine

    plugins to implement SKI combinator calculus • I used taiki45/ruboty-echo and r7kamura/ruboty-replace • I’ll describe these plguins
  16. ruboty-echo

  17. ruboty-echo • “Ruboty repeats everything...” • It’s super simple. •

    ruboty echo hello ◦ => Ruboty says “hello”
  18. HACK: ruboty reacts itself

  19. ruboty-replace

  20. ruboty-replace • “Replace given message with registered patterns for other

    handlers.” • Like alias • example ◦ ruboty replace hello (.+) with echo こんにちは \1 さん ◦ “ruboty hello pocke” will be replaced with “ruboty echo こんにちは pocke さん”
  21. String#gsub! • ruboty-replace just uses String#gsub! • For example: ◦

    ruboty replace hello (.+) with echo こんにちは \1 さん ◦ msg.gsub!(/hello (.+)/, “echo こんにちは \1 さん”)
  22. Combine them

  23. Make a loop (DO NOT TRY IT⚠) • We can

    make an infinite loop with them easily • Just say the following command⚠ ◦ ruboty replace loop with echo ruboty loop • If you say “ruboty loop”, ruboty says “ruboty loop”, then ruboty says “ruboty loop”, then ruboty says “ruboty loop”, then ruboty says “ruboty loop”, then ruboty says “ruboty loop”, then ruboty says “ruboty loop”,
  24. It means we get “while” expression • It equals “while

    true do … end” • And, we already have String#gsub! by ruboty-replace • If we can implement SKI only by “while” and gsub!, we can implement SKI with the plugins
  25. The regular expressions (?<simple>(?:[()]|[^ski])*)s(?<expr1>[^()]|\(\g<expr1> +\))(?<expr2>[^()]|\(\g<expr2>+\))(?<expr3>[^()]|\(\g< expr3>+\))(?<rest>.*) (?<simple>(?:[()]|[^ski])*)k(?<expr1>[^()]|\(\g<expr1> +\))(?<expr2>[^()]|\(\g<expr2>+\))(?<rest>.*)$ (?<simple>(?:[()]|[^ski])*)\((?<content>(?<expr1>[^()] |\(\g<expr1>+\))*)\)(?<rest>.*)

    (?<simple>(?:[()]|[^ski])*)i(?<rest>.+) (?<simple>(?:[()]|[^ski])*)$ (?<content>.*[ski].*)$
  26. The result

  27. How create the regexps

  28. expr_gen expr_gen = -> (n) { "(?<expr#{n}> [^()] | \\(\\g<expr#{n}>+\\))

    " } • Generate a string that matches an “expression” • Recursive regexp by “\g”
  29. simple simple = '(?<simple>(?: [()] | [^ski])*) ' • String

    that matches simple string • Simple string is not calculated
  30. I I = /^#{simple}i(?<rest>.+)/ $i = '\k<simple>\k<rest>'

  31. K K = /^#{simple}k#{expr_gen.(1)}#{expr_ge n.(2)}(?<rest>.*)$/ $k = '\k<simple>\k<expr1>\k<rest>'

  32. S S = /^#{simple}s#{expr_gen.(1)}#{expr_ge n.(2)}#{expr_gen.(3)}(?<rest>.*)/ $s = '\k<simple>(\k<expr1>\k<expr3>)(\k<e xpr2>\k<expr3>)\k<rest>'

  33. Reduce parens P = /^#{simple}\((?<content>#{expr_gen.( 1)}*)\)(?<rest>.*)/ $p = '\k<simple>\k<content>\k<rest>'

  34. while and gsub! def ski(str) () while str.gsub!(S, $s) ||

    str.gsub!(K, $k) || str.gsub!(I, $i) || str.gsub!(P, $p) str end
  35. Conclusion

  36. Conclusion • We learn Ruboty and SKI, and Regexp •

    We can implement SKI in Slack without “code” • For more information: ◦ The Ruby program: https://bit.ly/2RI1Ckd ◦ Japanese blog: https://bit.ly/2vs0fNE Thanks for listening!