Class: Proc

Inherits:
Object show all
Defined in:
lib/mug/apply.rb,
lib/mug/functional.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.const(c) ⇒ Proc

Note:

It always returns the same object, so mutations will stick from invocation to invocation.

Generates a constant function that always returns c.

Parameters:

  • c (Object)

    the constant value to return

Returns:

  • (Proc)

    a function that always returns c



213
214
215
# File 'lib/mug/functional.rb', line 213

def const c
  lambda {|*| c }
end

.identityProc

Generates an identity function that always returns its argument exactly.

Returns:

  • (Proc)

    an identity function



200
201
202
# File 'lib/mug/functional.rb', line 200

def identity
  lambda {|x| x }
end

.juxt(*funcs) ⇒ Proc

Generates a function that maps its arguments to the given funcs list in order.

Examples:

require 'mug/functional'
func = Proc.juxt :upcase, :downcase, :length
func.call 'AbC'   #=> ['ABC', 'abc', 3]

Parameters:

  • funcs (Array<#to_proc>)

    functions to apply to the arguments

Returns:

  • (Proc)

    a function that applies each func to its arguments



189
190
191
192
193
# File 'lib/mug/functional.rb', line 189

def juxt *funcs
  lambda do |*args|
    funcs.map {|f| f.to_proc.call(*args) }
  end
end

Instance Method Details

#apply(*args) ⇒ Object, Proc

Curries this Proc and partially applies parameters. If a sufficient number of arguments are supplied, it passes the supplied arguments to the original proc and returns the result. Otherwise, returns another curried proc that takes the rest of arguments.

Parameters:

  • args (Array)

    the arguments to partially apply

Returns:

  • (Object, Proc)

    the result if sufficient args, or a curried Proc



16
17
18
19
20
21
22
23
24
25
# File 'lib/mug/apply.rb', line 16

def apply(*args)
  n = arity < 0 ? -arity - 1 : arity
  if lambda?
    curry(n).call(*args)
  elsif args.length >= n
    call(*args)
  else
    proc {|*more| call(*args, *more) }
  end
end

#compose(*funcs) ⇒ Proc

Composes a sequence of functions.

A function is anything that responds to #to_proc, so symbols are allowed.

This proc is prepended at the start of the composition.

Examples:

require 'mug/functional'
func = ->(x) { x.inspect }
func2 = func.compose(:to_s, :length)
func2[123]    #=> 3

Parameters:

  • funcs (Array<#to_proc>)

    functions to compose after this one

Returns:

  • (Proc)

    the composed function



21
22
23
24
# File 'lib/mug/functional.rb', line 21

def compose *funcs
  return self if funcs.empty?
  self >> funcs.map(&:to_proc).reduce(:>>)
end

#mapply(*args) ⇒ Array

Applies this function to each element of args in order.

proc.mapply(*args) is equivalent to args.map(&proc)

Parameters:

  • args (Array)

    elements to apply this function to

Returns:

  • (Array)

    the results of applying this function to each element



56
57
58
# File 'lib/mug/functional.rb', line 56

def mapply *args
  args.map {|*a| self.call(*a) }
end

#memoizeProc Also known as: memoise

Generates a function that memoizes this one. For a given set of parameters, this proc is only invoked once; the result is remembered for subsequent invocations.

Examples:

require 'mug/functional'
func = lambda do |x|
  puts x
  x
end
func2 = func.memoize
func2[1]  #=> prints "1", returns 1
func2[1]  #=> returns 1 immediately

Returns:

  • (Proc)

    a memoized version of this function



77
78
79
80
81
82
# File 'lib/mug/functional.rb', line 77

def memoize
  cache = {}
  lambda do |*args|
    cache.fetch(args) {|_| cache[args] = self.call(*args) }
  end
end

#precompose(*funcs) ⇒ Proc

Composes a sequence of functions.

A function is anything that responds to #to_proc, so symbols are allowed.

This proc is appended at the end of the composition.

Examples:

require 'mug/functional'
func = ->(x) { x.inspect }
func2 = func.precompose(:to_s, :length)
func2[123]    #=> "3"

Parameters:

  • funcs (Array<#to_proc>)

    functions to compose before this one

Returns:

  • (Proc)

    the composed function



43
44
45
46
# File 'lib/mug/functional.rb', line 43

def precompose *funcs
  return self if funcs.empty?
  self << funcs.map(&:to_proc).reduce(:>>)
end

#trans(*indices, arity: :min) ⇒ Proc

Generates a function that reorders its arguments according to indices and calls this function on the resulting list.

The arity parameter controls how mismatches in length between the arguments and indices are handled:

:min       - cap at the minimum of args and indices (default)
:max       - use the maximum; nil-fill if args are short,
           pass-through if args are long
:indices   - always use indices.size; nil for out-of-bounds
:arguments - always use args.size; excess positions pass
           through at their original index

Examples:

require 'mug/functional'
prc = ->(*a) { a }
prc.trans(1, 0).call(:a, :b, :c)  #=> [:b, :a]

Parameters:

  • indices (Array<Integer>)

    the new order of argument indices

  • arity (Symbol) (defaults to: :min)

    how to handle length mismatches

Returns:

  • (Proc)

    a function that reorders its arguments before calling this one



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/mug/functional.rb', line 108

def trans *indices, arity: :min
  case arity
  when :min
    lambda do |*a|
      n = [a.size, indices.size].min
      list = (0...n).map {|i| a[indices[i]] }
      self.call(*list)
    end
  when :indices
    lambda do |*a|
      list = (0...indices.size).map {|i| a[indices[i]] }
      self.call(*list)
    end
  when :arguments
    lambda do |*a|
      list = (0...a.size).map do |i|
        i < indices.size ? a[indices[i]] : a[i]
      end
      self.call(*list)
    end
  when :max
    lambda do |*a|
      n = [a.size, indices.size].max
      list = (0...n).map do |i|
        i < indices.size ? a[indices[i]] : a[i]
      end
      self.call(*list)
    end
  else
    raise ArgumentError, "unknown arity mode: #{arity.inspect}"
  end
end

#zipmap(*funcs) ⇒ Proc

Generates a function that maps its arguments to each of funcs in order.

Examples:

require 'mug/functional'
printer = ->(*x) { p x }
mapped_printer = printer.zipmap(:upcase, :downcase, :to_sym)
mapped_printer.call('Hello', 'There', 'Everyone') #=> ["HELLO", "there", :Everyone]

Parameters:

  • funcs (Array<#call, Symbol, nil>)

    functions to apply to each argument

Returns:

  • (Proc)

    a function that transforms its arguments before calling this one



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/mug/functional.rb', line 154

def zipmap *funcs
  lambda do |*args|
    n = [args.size, funcs.size].min
    mapped = (0...n).map do |i|
      func = funcs[i]
      arg  = args[i]

      if func.nil?
        arg
      elsif func.respond_to? :call
        func.call arg
      elsif func.is_a? Symbol
        arg.__send__ func
      else
        raise TypeError, "expected callable, Symbol, or nil; got #{func.class}"
      end
    end
    self.call(*mapped)
  end
end