Skip to content

Instantly share code, notes, and snippets.

@shved
Forked from flash-gordon/run_state.rb
Created February 17, 2019 10:25
Show Gist options
  • Save shved/dddf9b6ec986e279149e95e774249a9b to your computer and use it in GitHub Desktop.
Save shved/dddf9b6ec986e279149e95e774249a9b to your computer and use it in GitHub Desktop.
This shows that implementation of state effects doesn't require mutation. This example uses recursion that can be optimized after enabling TCO
require 'fiber'
class RunState
def call(fiber, state = {}, *xs)
result = fiber.resume(*xs)
if fiber.alive?
op, *args = result
case op
when :read
name = args[0]
call(fiber, state, state.fetch(name))
when :write
name, value = args
call(fiber, state.merge(name => value))
end
else
result
end
end
end
module State
def read(name)
Fiber.yield([:read, name])
end
def write(name, value)
Fiber.yield([:write, name, value])
end
end
require_relative 'run_state'
def main
State.write(:foo, 1)
puts(State.read(:foo))
State.write(:bar, "baz")
puts(State.read(:bar))
"done"
end
run = RunState.new.freeze
fiber = Fiber.new { main }
puts run.(fiber)
__END__
1
baz
done
RubyVM::InstructionSequence.compile_option = {
tailcall_optimization: true,
trace_instruction: false
}
require_relative 'run_state'
def deep_calc
State.write(:n, 0)
20000.times do
State.write(:n, State.read(:n) + 1)
end
State.read(:n)
end
run = RunState.new.freeze
fiber = Fiber.new { deep_calc }
puts run.(fiber)
__END__
20000
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment