Upcoming SlideShare
×

# Feeling Objects: Pattern Matching in Ruby

612 views

Published on

0 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

• Be the first to like this

Views
Total views
612
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
3
0
Likes
0
Embeds 0
No embeds

No notes for slide

### Feeling Objects: Pattern Matching in Ruby

1. 1. Friday, April 5, 13
2. 2. Feel Objects Pattern Matching in RubyFriday, April 5, 13
3. 3. Name: Ryan LevickFriday, April 5, 13
4. 4. Work: 6WunderkinderFriday, April 5, 13
5. 5. Twitter: @itchyanklesFriday, April 5, 13
6. 6. Friday, April 5, 13
7. 7. What the hell is pattern matching and why should I care?Friday, April 5, 13
8. 8. Wikipedia Deﬁnition “...the act of checking a perceived sequence of tokens for the presence of the constituents of some pattern.”Friday, April 5, 13
9. 9. Wat?Friday, April 5, 13
10. 10. My Best Try Checking a data type against some predeﬁned patterns, and when that data type matches one of the predeﬁned patterns, do something.Friday, April 5, 13
11. 11. In Short... Pattern matching is another way to do control ﬂow.Friday, April 5, 13
12. 12. Death to “if-then-else”!Friday, April 5, 13
13. 13. Friday, April 5, 13
14. 14. ein BeispielFriday, April 5, 13
15. 15. fun sum(numbers) = case numbers of [] => 0 x::xs => x + sum(xs)Friday, April 5, 13
16. 16. I don’t know SML. What the hell is this?Friday, April 5, 13
17. 17. Function declaration fun sum(numbers) = case numbers of [] => 0 x::xs => x + sum(xs)Friday, April 5, 13
18. 18. Case statement matching against the list “numbers”. fun sum(numbers) = case numbers of [] => 0 x::xs => x + sum(xs)Friday, April 5, 13
19. 19. First pattern fun sum(numbers) = case numbers of [] => 0 x::xs => x + sum(xs)Friday, April 5, 13
20. 20. Second pattern fun sum(numbers) = case numbers of [] => 0 x::xs => x + sum(xs)Friday, April 5, 13
21. 21. So let’s call it!Friday, April 5, 13
22. 22. val numbers = [1, 6, 8] sum(numbers)Friday, April 5, 13
23. 23. sum([1, 6, 8]) = case numbers of [] => 0 x::xs => x + sum(xs)Friday, April 5, 13
24. 24. What pattern does numbers match?Friday, April 5, 13
25. 25. x::xs => x + sum(xs) 1::[6, 8] => 1 + sum([6, 8])Friday, April 5, 13
26. 26. x::xs => x + sum(xs) 6::[8] => 1 + 6 + sum([8])Friday, April 5, 13
27. 27. x::xs => x + sum(xs) 8::[] => 1 + 6 + 8 + sum([])Friday, April 5, 13
28. 28. sum([]) = case numbers of [] => 0 x::xs => x + sum(xs)Friday, April 5, 13
29. 29. What pattern does numbers match?Friday, April 5, 13
30. 30. [] => 1 + 6 + 8 + 0 15Friday, April 5, 13
31. 31. Pretty easy, and could be implemented in roughly the same amount of characters with “if-then-else”Friday, April 5, 13
32. 32. (* Note: hd(list) takes the first element of list tl(list) takes all other elements of list *) fun sum(numbers) = if numbers = [] then 0 else hd(numbers) + sum(tl(numbers))Friday, April 5, 13
33. 33. Friday, April 5, 13
34. 34. So maybe you’re not convinced... Let’s try an example that’s even more interesting with pattern matching.Friday, April 5, 13
35. 35. Who knows FizzBuzz?Friday, April 5, 13
36. 36. // `~` in Rust is for allocating memory fn main() { for int::range(1, 101) |num| { io::println( match (num % 3, num % 5) { (0, 0) => ~"FizzBuzz", // must come first (0, _) => ~"Fizz", (_, 0) => ~"Buzz", (_, _) => int::str(num) // must come last } ); } } // Source: Lindsey Kuper’s FizzBuzz revisited (http://composition.al/blog/2013/03/02/ fizzbuzz-revisited/)Friday, April 5, 13
37. 37. The real heart of the function: match (num % 3, num % 5) { (0, 0) => ~"FizzBuzz", // must come first (0, _) => ~"Fizz", (_, 0) => ~"Buzz", (_, _) => int::str(num) // must come last }Friday, April 5, 13
38. 38. That’s nice and all, but there’s more...Friday, April 5, 13
39. 39. Both SML and Rust are strongly typed, and they let us deﬁne our own types. We can then match against those types.Friday, April 5, 13
40. 40. enum Remainder { zero, other(NonZeroRem) } enum NonZeroRemainder { one, two, three, four }Friday, April 5, 13
41. 41. fn int_to_rem(num: int) -> Remainder { match num { 0 => zero, 1 => other(one), 2 => other(two), 3 => other(three), 4 => other(four), _ => fail } }Friday, April 5, 13
42. 42. fn main() { for int::range(1, 101) |num| { io::println( match (int_to_rem(num % 3), int_to_rem(num % 5)) { (other(_), other(_)) => int::str(num), (zero, other(_)) => ~"Fizz", (other(_), zero) => ~"Buzz", (zero, zero) => ~"FizzBuzz" } ); } }Friday, April 5, 13
43. 43. Again the heart of the function: match (int_to_rem(num % 3), int_to_rem(num % 5)) { (other(_), other(_)) => int::str(num), (zero, other(_)) => ~"Fizz", (other(_), zero) => ~"Buzz", (zero, zero) => ~"FizzBuzz" }Friday, April 5, 13
44. 44. Pattern Matching is powerful. It allows us to easily change FizzBuzzFriday, April 5, 13
45. 45. match (int_to_rem(num % 3), int_to_rem(num % 5)) { (other(two), other(one)) => ~"Zot", (other(x), other(y)) => int::str(x/y), (zero, other(_)) => ~"Fizz", (other(x), zero) => ~"Buzz" + int::str(x), (zero, zero) => ~"FizzBuzz" }Friday, April 5, 13
46. 46. Friday, April 5, 13
47. 47. So how about Pattern Matching in Ruby?Friday, April 5, 13
48. 48. pattern-match github.com/k-tsj/pattern-matchFriday, April 5, 13
49. 49. require pattern-match match(object) do with(pattern) do ... end with(pattern) do ... end ... end # patterns are binded variables available in blockFriday, April 5, 13
50. 50. x = match(0) do with(String) { “It’s a String!” } with(Fixnum) { “It’s a Fixnum!” } end print x #=> “It’s a Fixnum!”Friday, April 5, 13
51. 51. require pattern-match 1.upto(100) do |n| match([(n % 3),(n % 5)]) do with(_[0,0]) { puts "FizzBuzz" } with(_[0,_]) { puts "Fizz" } with(_[_,0]) { puts "Buzz" } with(_[_,_]) { puts n } end endFriday, April 5, 13
52. 52. It allows for some cool things!Friday, April 5, 13
53. 53. require pattern-match match([1, "2", 3.0, "four"]) do with(_[a & 1, b & Or(Float, String), c & Not(Fixnum), d]) with(_[a & Fixnum, b & Not(String), c, d & Not(“four”)]) end endFriday, April 5, 13
54. 54. Friday, April 5, 13