110

# Ruboty and SKI January 31, 2020

## 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
○ 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!

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 ﬁrst
one
● For example:
○ Kxy => x
○ K(xyz)(abc) => xyz
○ Kixy => iy => y

12. Rule S
● It takes three arguments, and returns “ﬁrst
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 difﬁcult 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 inﬁnite 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
(?(?:[()]|[^ski])*)s(?[^()]|\(\g
+\))(?[^()]|\(\g+\))(?[^()]|\(\g<
expr3>+\))(?.*)
(?(?:[()]|[^ski])*)k(?[^()]|\(\g
+\))(?[^()]|\(\g+\))(?.*)\$
(?(?:[()]|[^ski])*)\((?(?[^()]
|\(\g+\))*)\)(?.*)
(?(?:[()]|[^ski])*)i(?.+)
(?(?:[()]|[^ski])*)\$
(?.*[ski].*)\$

26. The result

27. How create the
regexps

28. expr_gen
expr_gen = -> (n) {
"(?
[^()] |
\\(\\g+\\))
"
}
● Generate a string that matches an “expression”
● Recursive regexp by “\g”

29. simple
simple =
'(?(?:
[()] |
[^ski])*)
'
● String that matches simple string
● Simple string is not calculated

30. I
I = /^#{simple}i(?.+)/
\$i = '\k\k'

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

32. S
S =
/^#{simple}s#{expr_gen.(1)}#{expr_ge
n.(2)}#{expr_gen.(3)}(?.*)/
\$s =
'\k(\k\k)(\kxpr2>\k)\k'

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

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”