Skip to content

Instantly share code, notes, and snippets.

@Whitespace
Created April 9, 2013 17:04
Show Gist options
  • Save Whitespace/5347441 to your computer and use it in GitHub Desktop.
Save Whitespace/5347441 to your computer and use it in GitHub Desktop.
Couldn't sleep, so I added some monads to Ruby
require "minitest/autorun"
module Monad
def return(val)
self.class.new(val)
end
def bind(&block)
self.return yield @value
end
end
class Identity
include Monad
attr_reader :value
def initialize(value)
@value = value
self
end
def ==(value)
@value == value
end
end
describe Identity do
it "#bind is a left-identity with respect to return" do
value = rand(100000)
monad = Identity.new(value)
monad.bind do |v|
Identity.new(v)
end.must_equal(monad)
end
it "#return is a right-identity with respect to bind" do
value = rand(100000)
rand1 = rand(100000)
f = lambda { |v| v + rand1 }
monad = Identity.new(value)
monad.bind(&f).must_equal f.call(value)
end
it "#bind is associative" do
value = rand(100000)
rand1 = rand(100000)
rand2 = rand(100000)
f = lambda { |v| v + rand1 }
g = lambda { |v| v + rand2 }
monad = Identity.new(value)
monad.bind do
f.call(g.call(value))
end.must_equal monad.bind(&f).bind(&g)
end
end
module Just
def just
self
end
end
class Nothing
def self.just
self
end
def just
self.class
end
end
class Object
include Just
end
class Maybe
include Monad
attr_reader :value
def initialize(value)
@value = value
end
def fetch
@value.just
end
def bind(&block)
self.return case fetch
when Nothing then Nothing
else yield @value
end
end
def ==(value)
fetch == value
end
end
describe Maybe do
it "#bind is a left-identity with respect to return" do
value = rand(100000)
monad = Maybe.new(value)
monad.bind do |v|
Maybe.new(v)
end.must_equal(monad)
end
it "#return is a right-identity with respect to bind" do
value = rand(100000)
rand1 = rand(100000)
f = lambda { |v| v + rand1 }
monad = Maybe.new(value)
monad.bind(&f).must_equal f.call(value)
end
it "#bind is associative" do
value = rand(100000)
rand1 = rand(100000)
rand2 = rand(100000)
f = lambda { |v| v + rand1 }
g = lambda { |v| v + rand2 }
monad = Maybe.new(value)
monad.bind do
f.call(g.call(value))
end.must_equal monad.bind(&f).bind(&g)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment