Class: Object
- Inherits:
- BasicObject
- Defined in:
- lib/funtools/cons.rb,
lib/funtools/types.rb,
lib/funtools/recursion.rb,
lib/funtools/composition.rb,
lib/funtools/pattern-matching.rb
Instance Method Summary collapse
-
#compose(*f) ⇒ Object
Public: Compose a series of functions.
-
#cons(left, right) ⇒ Object
Public: Wrap Cons.new to construct a new Cons cell.
-
#defix(sym, &block) ⇒ Object
Public: Define a method in the current scope which will execute a given block recursively until a fixpoint is reached.
-
#defpattern(sym) ⇒ Object
Public: Define a method in the current scope which allow pattern matching function declaration to be used.
-
#deftail(sym, &block) ⇒ Object
Public: Define a method in the current scope which will execute a given block in such a manner that recursive calls are handled properly so long as the call constitutes tail recursion.
-
#list(first, second = nil, *rest) ⇒ Object
Public: Construct a list of nested Cons cells.
-
#pl(data, *f) ⇒ Object
Public: Mimic the -> macro in Clojure.
Instance Method Details
#compose(*f) ⇒ Object
Public: Compose a series of functions.
f - Any number of Procs, Methods, or Symbols which should be composed. If
functions f, g, and h are composed in that order, the result will be
f . g . h -> f(g(h(...)))
Returns a composed Proc.
33 34 35 36 37 |
# File 'lib/funtools/composition.rb', line 33 def compose(*f) f.map do |g| g.is_a?(Array) ? ->(n) { g.first.to_proc[n,*g.drop(1)] } : g.to_proc end.reduce(&:*) end |
#cons(left, right) ⇒ Object
Public: Wrap Cons.new to construct a new Cons cell.
left - Any Object to be the left element of the cell. right - Any Object to be the right element of the cell.
Returns a Cons cell.
8 9 10 |
# File 'lib/funtools/cons.rb', line 8 def cons(left, right) Cons.new(left, right) end |
#defix(sym, &block) ⇒ Object
Public: Define a method in the current scope which will execute a given block recursively until a fixpoint is reached.
sym - Symbol defining the name of the method to be created. block - Block containing the logic for the function to be created.
Returns nothing.
13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/funtools/recursion.rb', line 13 def defix(sym, &block) = :define_method if respond_to?(:define_method, true) ||= :define_singleton_method self.send(, sym) do |*n| last = nil [1].cycle.reduce(n) do |c, e| break c if last == c last = c instance_exec(c, &block) end end end |
#defpattern(sym) ⇒ Object
Public: Define a method in the current scope which allow pattern matching function declaration to be used.
sym - Symbol defining the name of the method to be created. block - Block containing the logic for the function to be created.
Returns nothing.
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/funtools/pattern-matching.rb', line 9 def defpattern(sym) match = ->(a, b) do if([a,b].map { |o| o.is_a?(Enumerable) && a.class == b.class }.all?) raise ArgumentError unless a.length == b.length zipped = a.is_a?(Hash) ? a.sort.zip(b.sort) : a.zip(b) zipped.reduce(true) do |c, e| c && match.(*e) end else a.nil? || a == b end end old_method = self.class.method(sym) if self.class.method_defined?(:sym) patterns = [] self.class.send(:define_method, sym) do |*l, &b| patterns << ->(*n) do ->(*m) do if m.length == n.length e = m.zip(n) raise NoMatch if e.reject { |e| match.(*e) }.any? instance_exec(*n, &b) end end.(*l) end end yield if old_method self.class.send(:define_method, sym, &old_method) else self.class.send(:remove_method, sym) end = :define_method if respond_to?(:define_method, true) ||= :define_singleton_method self.send(, sym) do |*args| patterns.each do |pattern| begin return instance_exec(*args, &pattern) rescue NoMatch end end instance_exec { raise NoMatch } end end |
#deftail(sym, &block) ⇒ Object
Public: Define a method in the current scope which will execute a given block in such a manner that recursive calls are handled properly so long as the call constitutes tail recursion.
sym - Symbol defining the name of the method to be created. block - Block containing the logic for the function to be created.
Returns nothing.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/funtools/recursion.rb', line 34 def deftail(sym, &block) = :define_method if respond_to?(:define_method, true) ||= :define_singleton_method self.send(, sym) do |*n| instance_exec { self.dup }.instance_exec do class << self self end.class_eval do define_method(sym) do |*a| a.reduce(Funtools::RecurseArgs.new) { |c,e| c << e } end end loop do n = instance_exec(*n, &block) return n unless n.is_a?(Funtools::RecurseArgs) end end end end |
#list(first, second = nil, *rest) ⇒ Object
Public: Construct a list of nested Cons cells.
first - Any Object to be the leftmost element of the list. second - Any Object to be the second element of the list (default: nil). rest - Any number of Objects to serve as elements in the list.
Returns a list (nested Cons cells).
19 20 21 22 |
# File 'lib/funtools/cons.rb', line 19 def list(first, second = nil, *rest) set = (rest.empty? && second.nil?) ? [] : rest + [nil] ([first, second] + set).reverse.reduce { |c, e| Cons.new(e, c) } end |
#pl(data, *f) ⇒ Object
Public: Mimic the -> macro in Clojure.
data - Any data to be passed to the composed function. f - Any number of Procs, Methods, or Symbols which should be composed.
If functions f, g, and h are composed in that order, the result will
be f . g . h -> f(g(h(...)))
Returns the result of the composed functions, called with data as the argument.
48 49 50 |
# File 'lib/funtools/composition.rb', line 48 def pl(data, *f) compose(*f.reverse)[*[data].flatten] end |