Pattern matching in Ruby
So, I’ve been reading “Practical OCaml” for the last couple days. I was impressed with the way OCaml handles pattern matching. Its not quite as succinct as in Haskell, but I believe its a bit more flexible. (Although I’m not great with Haskell, so I could be wrong)
Anyhow… I was reading Hacker News this evening and came across a post by Eric at http://blog.pretheory.com on pattern matching in Ruby.
It uses Raganwald’s domain-specific language code, which I have yet to use, but from looking at the code for a few moments, it seems pretty slick. Overall, a good addition to Ruby, in my opinion.
However…
Being that I’m reading about OCaml’s fabulous pattern matching at the moment, I see some shortcomings, which I’d like to address.
First is regular expression matching…
def which_country(n)
match n do
with(/\d{3}[ -]\d{3}[ -]\d{4}/) { "US phone number" }
with(/\d-\d{3} \d{2} \d{2}/) { "Chilean phone number" }
with(/\d{3} \d{2} \d{2} \d{2}/) { "French phone number" }
otherwise { "Quit making crap up..." }
end
end
By default, any call to this function would yield “Quit making crap up…”. However, due to the slick way in which Eric wrote the pattern matching code, all we need to add is this…
class Regexp
def patmatch(arg,mapping)
arg =~ self
end
end
Which allows us to yield…
> which_country("555 338 5913")
"US phone number"
> which_country("9-555 23 23")
"Chilean phone number"
> which_country("555 23 45 67")
"French phone number"
Not really any different than a case statement… but I like it anyway.
The second thing is referred to as “guarded matches” in OCaml. Essentially, each “with” is a boolean function.
def which_mod(n)
match n do
with( lambda{|n| n % 2 0} ) { "divisable by two" }
with( lambda{|n| n % 3 0} ) { “divisable by three” }
with( lambda{|n| n % 5 == 0} ) { “divisable by five” }
otherwise { “lets pretend its prime” }
end
end
> which_mod(4)
"divisable by two"
> which_mod(17)
"lets pretend its prime"
Getting this working is just as easy as getting regular expressions working.
class Proc
def patmatch(arg,mapping)
self.call(arg)
end
end
Have fun and thanks again for such a neat hack, Eric.