Functional
Ruby¶ ↑
A gem for adding functional programming tools to Ruby. Inspired by {Erlang}[http://www.erlang.org/], {Clojure}[http://clojure.org/], and {Functional Java}[http://functionaljava.org/].
Introduction¶ ↑
Two things I love are Ruby and functional programming. If you combine Ruby’s ability to create functions sans-classes with the power of blocks, proc
, and lambda
, Ruby code can follow just about every modern functional programming design paradigm. Add to this Ruby’s vast metaprogramming capabilities and Ruby is easily one of the most powerful languages in common use today.
Goals¶ ↑
Our goal is to implement various functional programming patterns in Ruby. Specifically:
-
Be an ‘unopinionated’ toolbox that provides useful utilities without debating which is better or why
-
Remain free of external gem dependencies
-
Stay true to the spirit of the languages providing inspiration
-
But implement in a way that makes sense for Ruby
-
Keep the semantics as idiomatic Ruby as possible
-
Support features that make sense in Ruby
-
Exclude features that don’t make sense in Ruby
-
Keep everything small
-
Be as fast as reasonably possible
Features¶ ↑
The primary site for documentation is the automatically generated API documentation.
-
Protocol specifications inspired by Clojure protocol, Erlang behavior, and Objective-C protocol.
-
Function overloading with Erlang-style function pattern matching.
-
Simple, thread safe, immutable data structures, such as
Record
,Union
, andTuple
, inspired by Clojure, Erlang, and other functional languages. -
Thread safe, immutable
Either
andOption
classes based on Functional Java and Haskell. -
Memoization of class methods based on Clojure memoize.
-
Lazy execution with a
Delay
class based on Clojure delay. -
ValueStruct
, a simple, thread safe, immutable variation of Ruby’s OpenStruct class. -
Thread safe data structures, such as
FinalStruct
andFinalVar
, which can be written to at most once before becoming immutable. Based on {Java’sfinal
keyword}[http://en.wikipedia.org/wiki/Final_(Java)].
Supported Ruby Versions¶ ↑
MRI 2.0 and higher, JRuby (1.9 mode), and Rubinius 2.x. This library is pure Ruby and has no gem dependencies. It should be fully compatible with any interpreter that is compliant with Ruby 2.0 or newer.
Install¶ ↑
gem install functional-ruby
or add the following line to Gemfile:
gem 'functional-ruby'
and run bundle install
from your shell.
Once you’ve installed the gem you must require
it in your project:
require 'functional'
Examples¶ ↑
Specifying a protocol:
Functional::SpecifyProtocol(:Name) do attr_accessor :first attr_accessor :middle attr_accessor :last attr_accessor :suffix end
Defining immutable data structures including Either, Option, Union and Record
Name = Functional::Record.new(:first, :middle, :last, :suffix) do mandatory :first, :last default :first, 'J.' default :last, 'Doe' end anon = Name.new #=> #<record Name :first=>"J.", :middle=>nil, :last=>"Doe", :suffix=>nil> matz = Name.new(first: 'Yukihiro', last: 'Matsumoto') #=> #<record Name :first=>"Yukihiro", :middle=>nil, :last=>"Matsumoto", :suffix=>nil>
Pattern matching using protocols, type checking, and other options:
class Foo include Functional::PatternMatching include Functional::Protocol include Functional::TypeCheck def greet return 'Hello, World!' end defn(:greet, _) do |name| "Hello, #{name}!" end defn(:greet, _) { |name| "Pleased to meet you, #{name.full_name}!" }.when {|name| Type?(name, CustomerModel, ClientModel) } defn(:greet, _) { |name| "Hello, #{name.first} #{name.last}!" }.when {|name| Satisfy?(name, :Name) } defn(:greet, :doctor, _) { |name| "Hello, Dr. #{name}!" } defn(:greet, nil, _) { |name| "Goodbye, #{name}!" } defn(:greet, _, _) { |_, name| "Hello, #{name}!" } end
Performance improvement of idempotent functions through memoization:
class Factors include Functional::Memo def self.sum_of(number) of(number).reduce(:+) end def self.of(number) (1..number).select {|i| factor?(number, i)} end def self.factor?(number, potential) number % potential == 0 end memoize(:sum_of) memoize(:of) end
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
License and Copyright¶ ↑
Functional Ruby is free software released under the MIT License.