Skip to content
vic

tomstuart/monads

Simple Ruby implementations of some common monads.

tomstuart/monads.json
{
"createdAt": "2014-08-02T13:52:07Z",
"defaultBranch": "master",
"description": "Simple Ruby implementations of some common monads.",
"fullName": "tomstuart/monads",
"homepage": "https://tomstu.art/refactoring-ruby-with-monads",
"language": "Ruby",
"name": "monads",
"pushedAt": "2019-09-08T09:18:50Z",
"stargazersCount": 616,
"topics": [],
"updatedAt": "2025-11-14T07:04:27Z",
"url": "https://github.com/tomstuart/monads"
}

This library provides simple Ruby implementations of some common monads.

The most important method of each implementation is #and_then (a.k.a. bind or >>=), which is used to connect together a sequence of operations involving the value(s) inside the monad. Each monad also has a .from_value class method (a.k.a. return or unit) for constructing an instance of that monad from an arbitrary value.

(a.k.a. the maybe monad)

An Optional object contains a value that might be nil.

>> require 'monads/optional'
=> true
>> include Monads
=> Object
>> optional_string = Optional.new('hello world')
=> #<struct Monads::Optional value="hello world">
>> optional_result = optional_string.and_then { |string| Optional.new(string.upcase) }
=> #<struct Monads::Optional value="HELLO WORLD">
>> optional_result.value
=> "HELLO WORLD"
>> optional_string = Optional.new(nil)
=> #<struct Monads::Optional value=nil>
>> optional_result = optional_string.and_then { |string| Optional.new(string.upcase) }
=> #<struct Monads::Optional value=nil>
>> optional_result.value
=> nil

(a.k.a. the list monad)

A Many object contains multiple values.

>> require 'monads/many'
=> true
>> include Monads
=> Object
>> many_strings = Many.new(['hello world', 'goodbye world'])
=> #<struct Monads::Many values=["hello world", "goodbye world"]>
>> many_results = many_strings.and_then { |string| Many.new(string.split(/ /)) }
=> #<struct Monads::Many values=["hello", "world", "goodbye", "world"]>
>> many_results.values
=> ["hello", "world", "goodbye", "world"]

(a.k.a. the continuation monad)

An Eventually object contains a value that will eventually be available, perhaps as the result of an asynchronous process (e.g. a network request).

>> require 'monads/eventually'
=> true
>> include Monads
=> Object
>> eventually_string = Eventually.new do |success|
Thread.new do
sleep 5
success.call('hello world')
end
end
=> #<struct Monads::Eventually block=#<Proc>>
>> eventually_result = eventually_string.and_then do |string|
Eventually.new do |success|
Thread.new do
sleep 5
success.call(string.upcase)
end
end
end
=> #<struct Monads::Eventually block=#<Proc>>
>> eventually_result.run { |string| puts string }
=> #<Thread run>
HELLO WORLD