Created
April 26, 2013 16:19
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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]