Funkify
Haskell-style partial application and composition for Ruby methods
"In computer science, partial application refers to the process of fixing a number of arguments to a function, producing another function of smaller arity." --Wikipedia
Curring in Haskell
Partial application in Haskell
Function composition in Haskell
Usage
class MyFunkyClass
include Funkify
def add(x, y)
x + y
end
# we make a specific method autocurried using the auto_curry method
auto_curry :add
# alternatively, if we invoke auto_curry without a parameter
# then all subsequent methods will be autocurried
auto_curry
def mult(x, y)
x * y
end
def negate(x)
-x
end
end
Partial application and currying
When a method supports autocurrying it can still be invoked normally (if all parameters are provided) however if less than the required number are given a Proc
is returned
with the given parameters partially applied:
funky = MyFunkyClass.new
funky.add(1, 2) #=> This works normally and returns 3
add_1 = funky.add(1) #=> The `1` is partially applied and a `Proc` is returned
add_1.(2) #=> We invoke that `Proc` with the remaining argument and the final result (`3`) is returned.
Function composition
We compose methods using the *
and |
operators.
*
composes right to left, this is the standard way to compose functions found in languages like Haskell:
(mult(5) * add(1)).(10) #=> 55
# We can further compose the above with another method:
(negate * mult(5) * add(1)).(10) #=> -55
|
composes left to right, like a shell pipeline:
(mult(5) | add(1) | negate).(3) #=> -16
As a cute bonus, we can inject values from the left into a pipeline with the pass
method (see more):
pass(3) | (mult(5) | add(1) | negate) #=> -16
Other examples:
Add 10 to every item in an Enumerable:
(1..5).map &funky.add(10) #=> [11, 12, 13, 14, 15]
Multiply by 10 and negate every item in an Enumerable:
(1..5).map &(funky.negate * funky.mult(10)) => [-10, -20, -30, -40, -50]
Installation
Add this line to your application's Gemfile:
gem 'funkify'
And then execute:
$ bundle
Or install it yourself as:
$ gem install funkify
Dedication
This library was inspired in part by stimulating conversations with epitron on Freenode.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request