Skip to content

Instantly share code, notes, and snippets.

@timcowlishaw
Created April 26, 2013 16:19
Show Gist options
  • Save timcowlishaw/5468491 to your computer and use it in GitHub Desktop.
Save timcowlishaw/5468491 to your computer and use it in GitHub Desktop.
A Ruby approximation of the Continuation Monad from Haskell, inspired by Dan Piponi's FPComplete tutorial, "The Mother of All Monads": https://www.fpcomplete.com/user/dpiponi/the-mother-of-all-monads
# Inspired by https://www.fpcomplete.com/user/dpiponi/the-mother-of-all-monads, A ruby port of Haskell's continuation monad, using fibers for lazily-evaluated giggles:
#
# For reference, The continuation monad instance definition from haskell:
# instance Monad (Cont r) where
# return a = Cont ($ a)
# m >>= k = Cont $ \c -> runCont m $ \a -> runCont (k a) c
#HI THERE, I AM THE CONTINUATION MONAD
class Cont
def self.unit(x)
Cont.new {|nxt| nxt.call(x) }
end
def initialize(&block)
@block = block
end
def bind(&block)
this = self
Cont.new { |nxt|
this.run { |unwrapped|
result = block.call(unwrapped).run
nxt.call(result)
}
}
end
def run(&block)
block ||= lambda {|x| x }
@block.call(block)
end
#DID I MENTION I AM ALSO A FUNCTOR
def map(&block)
bind {|x| Cont.unit(block.call(x)) }
end
end
#HERE ARE SOME THINGS YOU CAN USE ME FOR
#LAZINESS!!!
puts "Doing some sums in the lazy continuation monad"
m = Cont.unit(5).map {|x| puts("actually doing the work now"); x ** 2 }
puts "got our monad right here"
result = m.run
puts "the result is #{result}"
#EARLY TERMINATION!!!
print "x on a good day:"
mx = Cont.unit(11)
my = mx.bind {|x|
Cont.unit((x + 1).to_s)
}
puts "Hi there x, Can you tell me what is the number after you?"
puts my.run
print "x on a bad day:"
mx = Cont.new { |nxt| "nah mate not interested" }
my = mx.bind {|x|
puts "This bit never happens"
Cont.unit((x + 1).to_s)
}
puts "Hi there x, Can you tell me what is the number after you?"
puts my.run
#CHOICE!!!
mx = Cont.new {|nxt| [nxt.call(1), nxt.call(2)] }
my = Cont.new {|nxt| [nxt.call(2), nxt.call(3)] }
mz = mx.bind {|x|
my.bind {|y|
Cont.unit(x * y)
}
}
puts "multiply all the numbers!"
puts mz.run.flatten.inspect
@timcowlishaw
Copy link
Author

And the output:

[80] pry(main)> edit monads.rb Doing some sums in the lazy continuation monad got our monad right here actually doing the work now the result is 25 x on a good day:Hi there x, Can you tell me what is the number after you? 12 x on a bad day:Hi there x, Can you tell me what is the number after you? nah mate not interested multiply all the numbers! [2, 3, 4, 6]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment