module Fear::PartialFunction
A partial function is a unary function defined on subset of all possible inputs. The method defined_at?
allows to test dynamically if an arg is in the domain of the function.
Even if defined_at?
returns true for given arg, calling call
may still throw an exception, so the following code is legal:
@example Fear.case(->(_) { true }) { 1/0 }
It is the responsibility of the caller to call defined_at?
before calling call
, because if defined_at?
is false, it is not guaranteed call
will throw an exception to indicate an error guard. If an exception is not thrown, evaluation may result in an arbitrary arg.
The main distinction between PartialFunction
and Proc
is that the user of a PartialFunction
may choose to do something different with input that is declared to be outside its domain. For
example:
@example
sample = 1...10 is_even = Fear.case(->(arg) { arg % 2 == 0}) do |arg| "#{arg} is even" end is_odd = Fear.case(->(arg) { arg % 2 == 1}) do |arg| "#{arg} is odd" end
The method or_else
allows chaining another partial function to handle input outside the declared domain
numbers = sample.map(is_even.or_else(is_odd).to_proc)
@see github.com/scala/scala/commit/5050915eb620af3aa43d6ddaae6bbb83ad74900d @!method condition
describes the domain of partial function @return [#===] @abstract
@!method function
@return [#call] @abstract
Constants
- EMPTY
Public Class Methods
Creates partial function guarded by several condition. All guards should match. @param guards [<#===>] @param function [Proc] @return [Fear::PartialFunction]
# File lib/fear/partial_function.rb, line 162 def and(*guards, &function) PartialFunctionClass.new(Guard.and(guards), &function) end
Creates partial function guarded by several condition. Any
condition should match. @param guards [<#===>] @param function [Proc] @return [Fear::PartialFunction]
# File lib/fear/partial_function.rb, line 171 def or(*guards, &function) PartialFunctionClass.new(Guard.or(guards), &function) end
Public Instance Methods
@see and_then
# File lib/fear/partial_function.rb, line 146 def &(other) and_then(other) end
Composes this partial function with a fallback partial function (or Proc) which gets applied where this partial function is not defined.
@overload and_then
(other)
@param other [Fear::PartialFunction] @return [Fear::PartialFunction] a partial function with the same domain as this partial function, which maps argument +x+ to +other.(self.call(x))+. @note calling +#defined_at?+ on the resulting partial function may call the first partial function and execute its side effect. It is highly recommended to call +#call_or_else+ instead of +#defined_at?+/+#call+ for efficiency.
@overload and_then
(other)
@param other [Proc] @return [Fear::PartialFunction] a partial function with the same domain as this partial function, which maps argument +x+ to +other.(self.call(x))+.
@overload and_then
(&other)
@param other [Proc] @return [Fear::PartialFunction]
# File lib/fear/partial_function.rb, line 135 def and_then(other = Utils::UNDEFINED, &block) Utils.with_block_or_argument("Fear::PartialFunction#and_then", other, block) do |fun| if fun.is_a?(Fear::PartialFunction) Combined.new(self, fun) else AndThen.new(self, &fun) end end end
Calls this partial function with the given argument when it is contained in the function domain. Calls fallback function where this partial function is not defined.
@param arg [any] @yield [arg] if partial function not defined for this arg
@note that expression +pf.call_or_else(arg, &fallback)+ is equivalent to
+pf.defined_at?(arg) ? pf.(arg) : fallback.(arg)+ except that +call_or_else+ method can be implemented more efficiently to avoid calling +defined_at?+ twice.
# File lib/fear/partial_function.rb, line 88 def call_or_else(arg) if defined_at?(arg) call(arg) else yield arg end end
Checks if a value is contained in the function's domain.
@param arg [any] @return [Boolean]
# File lib/fear/partial_function.rb, line 60 def defined_at?(arg) condition === arg end
Turns this partial function in Proc-like object, returning Option
@return [#call]
# File lib/fear/partial_function.rb, line 152 def lift Lifted.new(self) end
Composes this partial function with a fallback partial function which gets applied where this partial function is not defined.
@param other [PartialFunction] @return [PartialFunction] a partial function which has as domain the union of the domains
of this partial function and +other+.
@example
handle_even = Fear.case(:even?.to_proc) { |x| "#{x} is even" } handle_odd = Fear.case(:odd?.to_proc) { |x| "#{x} is odd" } handle_even_or_odd = handle_even.or_else(odd) handle_even_or_odd.(42) #=> 42 is even handle_even_or_odd.(42) #=> 21 is odd
# File lib/fear/partial_function.rb, line 108 def or_else(other) OrElse.new(self, other) end
Converts this partial function to other
@return [Proc]
# File lib/fear/partial_function.rb, line 74 def to_proc proc { |arg| call(arg) } end
@see or_else
# File lib/fear/partial_function.rb, line 113 def |(other) or_else(other) end