-
-
Save pasberth/6460599 to your computer and use it in GitHub Desktop.
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
class DoNotation | |
class DSL | |
def initialize(&block) | |
@first_lets = [] | |
@proc_sources = [] | |
@variables = Hash[] | |
# evaluate DSL | |
instance_eval(&block) | |
bind = lambda do |head_source, tail_sources, get_symbol, lets| | |
proc do |x| | |
if get_symbol | |
@variables[get_symbol] = x | |
end | |
lets.each do |let_item| | |
@variables[let_item.symbol] = instance_eval(&let_item.block) | |
end | |
monad = instance_eval(&head_source.block) | |
if tail_sources.length > 0 | |
inner_proc = bind.call(tail_sources.first, tail_sources[1..-1], head_source.symbol, head_source.lets) | |
monad.flat_map(&inner_proc) | |
else | |
monad | |
end | |
end | |
end | |
@outermost_proc = bind.call(@proc_sources.first, @proc_sources[1..-1], nil, @first_lets) | |
end | |
def get(symbol, &block) | |
if symbol | |
self.class.send(:define_method, symbol) { @variables[symbol] } | |
end | |
@proc_sources << Struct.new(:symbol, :block, :lets).new(symbol, block, []) | |
end | |
def just(&block) | |
self.get(nil, &block) | |
end | |
def let(symbol, &block) | |
self.class.send(:define_method, symbol) { @variables[symbol] } | |
item = Struct.new(:symbol, :block).new(symbol, block) | |
if @proc_sources.length > 0 | |
@proc_sources.last.lets << item | |
else | |
@first_lets << item | |
end | |
end | |
def get_value() | |
@outermost_proc.call | |
end | |
end | |
include Enumerable | |
def initialize(&block) | |
@dsl = DSL.new(&block) | |
end | |
def each(&block) | |
value = @dsl.get_value | |
value.each(&block) | |
end | |
alias force to_a | |
end | |
def getLine | |
Enumerator.new { |y| | |
y << gets | |
}.lazy | |
end | |
def putStrLn(str) | |
Enumerator.new { |y| | |
puts str | |
y << nil | |
}.lazy | |
end | |
# this notation | |
main = DoNotation.new { | |
get(:i) { 5.times } | |
get(:x) { %w(a b c) } | |
just { ["(%d %s)" % [i, x]] } | |
} | |
p main.to_a | |
# ["(0 a)", "(0 b)", "(0 c)", "(1 a)", "(1 b)", "(1 c)", "(2 a)", "(2 b)", "(2 c)", "(3 a)", "(3 b)", "(3 c)", "(4 a)", "(4 b)", "(4 c)"] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment