Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

pp self ● Masataka “pocke” Kuwabara ● Work for BIt Journey, Inc. ● Live in ruby-jp.slack.com

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

What’s Ruboty

Slide 5

Slide 5 text

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.

Slide 6

Slide 6 text

Ruboty example

Slide 7

Slide 7 text

What’s SKI combinator calculus

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

Rule K ● “K” takes two arguments and returns the first one ● For example: ○ Kxy => x ○ K(xyz)(abc) => xyz ○ Kixy => iy => y

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

How implement SKI combinator calculus in Ruboty

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

ruboty-echo

Slide 17

Slide 17 text

ruboty-echo ● “Ruboty repeats everything...” ● It’s super simple. ● ruboty echo hello ○ => Ruboty says “hello”

Slide 18

Slide 18 text

HACK: ruboty reacts itself

Slide 19

Slide 19 text

ruboty-replace

Slide 20

Slide 20 text

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 さん”

Slide 21

Slide 21 text

String#gsub! ● ruboty-replace just uses String#gsub! ● For example: ○ ruboty replace hello (.+) with echo こんにちは \1 さん ○ msg.gsub!(/hello (.+)/, “echo こんにちは \1 さん”)

Slide 22

Slide 22 text

Combine them

Slide 23

Slide 23 text

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”,

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

The regular expressions (?(?:[()]|[^ski])*)s(?[^()]|\(\g +\))(?[^()]|\(\g+\))(?[^()]|\(\g< expr3>+\))(?.*) (?(?:[()]|[^ski])*)k(?[^()]|\(\g +\))(?[^()]|\(\g+\))(?.*)$ (?(?:[()]|[^ski])*)\((?(?[^()] |\(\g+\))*)\)(?.*) (?(?:[()]|[^ski])*)i(?.+) (?(?:[()]|[^ski])*)$ (?.*[ski].*)$

Slide 26

Slide 26 text

The result

Slide 27

Slide 27 text

How create the regexps

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Conclusion

Slide 36

Slide 36 text

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!