Haskell-style partial application and composition for Ruby methods
Ruby
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lib version 0.0.4 release Jul 13, 2013
spec Introduced >= (pipeline) operator Jul 13, 2013
.gitignore initial commit Jul 10, 2013
Gemfile initial commit Jul 10, 2013
LICENSE.txt
README.md Use Ruby 2.0 decorator syntax May 17, 2015
Rakefile version 0.0.3 release Jul 13, 2013
funkify.gemspec initial commit Jul 10, 2013

README.md

Funkify

Haskell-style partial application and composition for Ruby methods

Function composition when used in conjunction with partial application can yield exceptionally concise code, often more concise than the idiomatic Ruby. Check out the links below for further explanations of these features and examples of their use in Haskell:

Partial application in Haskell
Function composition in Haskell
Currying in Haskell

Also, watch this video to learn about some of the cool things you can do with function composition and partial application (the video is in Javascript but the ideas still apply to Ruby with Funkify)

Usage

Autocurrying

In order for a Ruby method to be amenable to partial application and composition it must first be autocurried:

class MyFunkyClass
  include Funkify

  # we make a specific method autocurried using the auto_curry method (Here with Ruby 2.0 decorator syntax)
  auto_curry def add(x, y)
    x + y
  end

  # 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) #=> 3 (We invoke that `Proc` with the remaining argument)

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 together with the >= (pipeline operator) (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

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request