Skip to content

Instantly share code, notes, and snippets.

@sampersand
Created February 7, 2021 10:25
Show Gist options
  • Save sampersand/02d56895bd198eae81e316fd26fcb37d to your computer and use it in GitHub Desktop.
Save sampersand/02d56895bd198eae81e316fd26fcb37d to your computer and use it in GitHub Desktop.
module FP
class MultiMethod
NoMethodMatchesError = Class.new StandardError
def initialize = @methods = []
def add(callable, conditions) = @methods.push([callable, conditions])
def call(...)
@methods.each do |callable, conditions|
return callable.(...) if conditions.all? {
next true if _1 == true
next false unless _1.respond_to?(:call)
_1.(...)
}
end
raise NoMethodMatchesError, "no method matched!"#, caller(1)
end
end
module_function
def extended(cls)
unless cls.instance_variable_defined? :@__multi_functions
cls.instance_variable_set :@__multi_functions, Hash.new { |h, k| h[k] = MultiMethod.new }
end
end
def multi(func_=nil, func: func_, where: [true])
where = [where] if where.respond_to? :call
@__multi_functions[func].add method(func), where
define_method func do |*a, **k, &b|
@__multi_functions[func].(*a, **k, &b)
end
end
def _(...) = method(...)
end
extend FP
multi def fib(x) = x,
where: proc { _1 <= 1 }
multi def fib(x) = fib(x - 1) + fib(x - 2)
print _(fib).<<()
10.times do |x|
puts fib x
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment