Skip to content

@britishtea /example.rb
Last active

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Simple pattern matching in Ruby that won't win any beauty contests.
require 'function'
# A fibonacci function.
fib = Function.new
fib[0] = 0
fib[1] = 1
fib[Integer] = ->(i) { fib[i - 2] + fib[i - 1] }
p fib[0] # => 0
p fib[20] # => 6765
fib["a"] rescue p $!
# => #<Function::TypeError: No matching pattern for "a".>
# An implementation of map.
map = Function.new
map[[], Function] = []
map[Array, Function] = ->(arr, f) { [f[arr[0]]] + map[arr[1..-1], f] }
p map[[0,1,2,5,20], fib]
p map[[0,1,2,5,20], fib]
# => [0, 1, 1, 5, 6765]
# Let's do some guarding. It ain't pretty.
fizzbuzz = Function.new
fizzbuzz[->(i) { i % 3 == 0 && i % 5 == 0 }] = "fizzbuzz"
fizzbuzz[->(i) { i % 3 == 0 }] = "fizz"
fizzbuzz[->(i) { i % 5 == 0 }] = "buzz"
fizzbuzz[:_] = ->(i) { i }
p map[1.upto(15).to_a, fizzbuzz]
# => [1, 2, "fizz", 4, "buzz", "fizz", 7, 8, "fizz", "buzz", 11, "fizz", 13, 14, "fizzbuzz"]
# A simple function with pattern matching.
class Function
WILDCARD = :_
TypeError = Class.new TypeError
def initialize(&block)
@patterns = Hash.new
end
# Public: Defines behaviour for a pattern.
def []=(*pattern, value)
@patterns[pattern] = value
end
# Public: Calls the function.
#
# Raises a Function::TypeError when no matching pattern was found.
def [](*args)
key, value = find_exact_match(args) || find_pattern_match(args)
if key.nil?
raise TypeError, "No matching pattern for #{args.inspect[1..-2]}."
end
if value.is_a? Proc
return value.call(*args)
else
return value
end
end
alias_method :call, :[]
def to_proc
proc { |*args| self[*args] }
end
private
# A set of values that are equal (#==) to another set of values.
# Example: [1,2,3] and [1,2,3]
def find_exact_match(arguments)
@patterns.find { |pattern, _| arguments == pattern }
end
# A set of values that are threequal (#===) to another set of values. Note
# that :_ is treated as a wildcard.
# Example: [Integer, Integer, :_] and [1,2,3].
def find_pattern_match(arguments)
@patterns.find do |pattern, _|
pattern.zip(arguments).all? do |one, two|
[ one == WILDCARD, # This is a wildcard.
one === two, # This executes Procs, we've got guards! :D
one == two
].any?
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.