Feeling Objects: Pattern Matching in Ruby

54
Friday, April 5, 13

description

 

Transcript of Feeling Objects: Pattern Matching in Ruby

Page 1: Feeling Objects: Pattern Matching in Ruby

Friday, April 5, 13

Page 2: Feeling Objects: Pattern Matching in Ruby

Feel ObjectsPattern Matching in Ruby

Friday, April 5, 13

Page 3: Feeling Objects: Pattern Matching in Ruby

Name: Ryan Levick

Friday, April 5, 13

Page 4: Feeling Objects: Pattern Matching in Ruby

Work: 6Wunderkinder

Friday, April 5, 13

Page 5: Feeling Objects: Pattern Matching in Ruby

Twitter : @itchyankles

Friday, April 5, 13

Page 6: Feeling Objects: Pattern Matching in Ruby

Friday, April 5, 13

Page 7: Feeling Objects: Pattern Matching in Ruby

What the hell is pattern matching and why should I

care?

Friday, April 5, 13

Page 8: Feeling Objects: Pattern Matching in Ruby

Wikipedia Definition

“...the act of checking a perceived sequence of tokens for the presence of the constituents of some pattern.”

Friday, April 5, 13

Page 9: Feeling Objects: Pattern Matching in Ruby

Wat?

Friday, April 5, 13

Page 10: Feeling Objects: Pattern Matching in Ruby

My Best Try

Checking a data type against some predefined patterns, and when that data type matches one of the predefined patterns, do something.

Friday, April 5, 13

Page 11: Feeling Objects: Pattern Matching in Ruby

In Short...

Pattern matching is another way to do control flow.

Friday, April 5, 13

Page 12: Feeling Objects: Pattern Matching in Ruby

Death to “if-then-else”!

Friday, April 5, 13

Page 13: Feeling Objects: Pattern Matching in Ruby

Friday, April 5, 13

Page 14: Feeling Objects: Pattern Matching in Ruby

ein Beispiel

Friday, April 5, 13

Page 15: Feeling Objects: Pattern Matching in Ruby

fun sum(numbers) = case numbers of

[] => 0x::xs => x + sum(xs)

Friday, April 5, 13

Page 16: Feeling Objects: Pattern Matching in Ruby

I don’t know SML. What the hell is this?

Friday, April 5, 13

Page 17: Feeling Objects: Pattern Matching in Ruby

Function declaration

fun sum(numbers) = case numbers of

[] => 0 x::xs => x + sum(xs)

Friday, April 5, 13

Page 18: Feeling Objects: Pattern Matching in Ruby

Case statement matching against the list “numbers”.

fun sum(numbers) = case numbers of [] => 0 x::xs => x + sum(xs)

Friday, April 5, 13

Page 19: Feeling Objects: Pattern Matching in Ruby

First pattern

fun sum(numbers) = case numbers of [] => 0 x::xs => x + sum(xs)

Friday, April 5, 13

Page 20: Feeling Objects: Pattern Matching in Ruby

Second pattern

fun sum(numbers) = case numbers of [] => 0 x::xs => x + sum(xs)

Friday, April 5, 13

Page 21: Feeling Objects: Pattern Matching in Ruby

So let’s call it!

Friday, April 5, 13

Page 22: Feeling Objects: Pattern Matching in Ruby

val numbers = [1, 6, 8]

sum(numbers)

Friday, April 5, 13

Page 23: Feeling Objects: Pattern Matching in Ruby

sum([1, 6, 8]) = case numbers of

[] => 0x::xs => x + sum(xs)

Friday, April 5, 13

Page 24: Feeling Objects: Pattern Matching in Ruby

What pattern does numbers match?

Friday, April 5, 13

Page 25: Feeling Objects: Pattern Matching in Ruby

x::xs => x + sum(xs)

1::[6, 8] => 1 + sum([6, 8])

Friday, April 5, 13

Page 26: Feeling Objects: Pattern Matching in Ruby

x::xs => x + sum(xs)

6::[8] => 1 + 6 + sum([8])

Friday, April 5, 13

Page 27: Feeling Objects: Pattern Matching in Ruby

x::xs => x + sum(xs)

8::[] => 1 + 6 + 8 + sum([])

Friday, April 5, 13

Page 28: Feeling Objects: Pattern Matching in Ruby

sum([]) = case numbers of

[] => 0x::xs => x + sum(xs)

Friday, April 5, 13

Page 29: Feeling Objects: Pattern Matching in Ruby

What pattern does numbers match?

Friday, April 5, 13

Page 30: Feeling Objects: Pattern Matching in Ruby

[] => 1 + 6 + 8 + 0

15

Friday, April 5, 13

Page 31: Feeling Objects: Pattern Matching in Ruby

Pretty easy, and could be implemented in roughly the same amount of characters with

“if-then-else”

Friday, April 5, 13

Page 32: Feeling Objects: Pattern Matching in Ruby

(* 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

Page 33: Feeling Objects: Pattern Matching in Ruby

Friday, April 5, 13

Page 34: Feeling Objects: Pattern Matching in Ruby

So maybe you’re not convinced...

Let’s try an example that’s even more interesting with pattern matching.

Friday, April 5, 13

Page 35: Feeling Objects: Pattern Matching in Ruby

Who knows FizzBuzz?

Friday, April 5, 13

Page 36: Feeling Objects: Pattern Matching in Ruby

// `~` 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

Page 37: Feeling Objects: Pattern Matching in Ruby

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

Page 38: Feeling Objects: Pattern Matching in Ruby

That’s nice and all, but there’s more...

Friday, April 5, 13

Page 39: Feeling Objects: Pattern Matching in Ruby

Both SML and Rust are strongly typed, and they let us define our own types.

We can then match against those types.

Friday, April 5, 13

Page 40: Feeling Objects: Pattern Matching in Ruby

enum Remainder { zero, other(NonZeroRem)}

enum NonZeroRemainder { one, two, three, four}

Friday, April 5, 13

Page 41: Feeling Objects: Pattern Matching in Ruby

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

Page 42: Feeling Objects: Pattern Matching in Ruby

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

Page 43: Feeling Objects: Pattern Matching in Ruby

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

Page 44: Feeling Objects: Pattern Matching in Ruby

Pattern Matching is powerful.

It allows us to easily change FizzBuzz

Friday, April 5, 13

Page 45: Feeling Objects: Pattern Matching in Ruby

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

Page 46: Feeling Objects: Pattern Matching in Ruby

Friday, April 5, 13

Page 47: Feeling Objects: Pattern Matching in Ruby

So how about Pattern Matching in Ruby?

Friday, April 5, 13

Page 48: Feeling Objects: Pattern Matching in Ruby

pattern-match

github.com/k-tsj/pattern-match

Friday, April 5, 13

Page 49: Feeling Objects: Pattern Matching in Ruby

require 'pattern-match'

match(object) do with(pattern) do ... end with(pattern) do ... end ...end

# patterns are binded variables available in block

Friday, April 5, 13

Page 50: Feeling Objects: Pattern Matching in Ruby

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

Page 51: Feeling Objects: Pattern Matching in Ruby

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

end

Friday, April 5, 13

Page 52: Feeling Objects: Pattern Matching in Ruby

It allows for some cool things!

Friday, April 5, 13

Page 53: Feeling Objects: Pattern Matching in Ruby

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

end

Friday, April 5, 13

Page 54: Feeling Objects: Pattern Matching in Ruby

Friday, April 5, 13