Skip to content

Instantly share code, notes, and snippets.

@jvoorhis
Created September 3, 2011 06:30
Show Gist options
  • Save jvoorhis/1190729 to your computer and use it in GitHub Desktop.
Save jvoorhis/1190729 to your computer and use it in GitHub Desktop.
class Action < Struct.new(:action)
def initialize(&block)
super block
end
def call
action.call
end
def seq(rhs)
self.class.new {
self.call
rhs.call
}
end
def self.noop
new {}
end
end
class Stream < Struct.new(:initial_state, :transition)
class Stop < StandardError
end
def initialize(init, &trans)
super init, trans
end
def self.generate(init, trans, done)
new(init) do |state, cont, skip, stop|
if done.(state)
stop.()
else
cont.(*trans.(state))
end
end
end
def self.iterate(init, &fn)
generate(
init,
-> x { fx = fn.(x); [fx, fx] },
-> _ { false }
)
end
def self.step(from, to, i)
generate(
from,
-> st { [st+i, st] },
-> st { st > to }
)
end
def self.repeat(val)
new(nil) do |_, cont, _, _|
cont.(nil, val)
end
end
def self.singleton(val)
new(true) do |state, cont, skip, stop|
if state
cont.(false, val)
else
stop.()
end
end
end
def self.empty
new(nil) do |_, _, _, stop|
stop.()
end
end
def inject(z, &fn)
state = initial_state
loop {
transition.(
state,
-> st, x { state = st; z = fn.(z, x) },
-> st { state = st },
-> { raise Stop, z }
)
}
rescue Stop => e
return e.message
end
def each(&action)
state = initial_state
loop do
transition.(
state,
-> st, x { state = st; action.(x) },
-> st { state = st },
-> { raise Stop, "finished" }
)
end
rescue Stop
end
def map(&fn)
self.class.new(initial_state) do |state, cont, skip, stop|
transition.(
state,
-> st, x { cont.(st, fn.(x)) },
skip,
stop
)
end
end
def select(&pred)
self.class.new(initial_state) do |state, cont, skip, stop|
transition.(
state,
-> st, x { if pred.(x) then cont.(st, x) else skip.(st) end },
skip,
stop
)
end
end
def reject
select { |x| !yield x }
end
def append(rhs)
self.class.new([:left, initial_state]) do |(tag, state), cont, skip, stop|
case tag
when :left
self.transition.(
state,
-> st, x { cont.([:left, st], x) },
-> st { skip.([:left, st]) },
-> { skip.([:right, rhs.initial_state]) }
)
when :right
rhs.transition.(
state,
-> st, x { cont.([:right, st], x) },
-> st { skip.([:right, st]) },
stop
)
end
end
end
def zip_with(rhs, &merge)
self.class.new(
[:left, self.initial_state, rhs.initial_state, nil]
) do |(tag, sa, sb, va), cont, skip, stop|
case tag
when :left
self.transition.(
sa,
-> st, va { skip.([:right, st, sb, va]) },
-> st { skip.([:left, st, sb, nil]) },
stop
)
when :right
rhs.transition.(
sb,
-> st, vb { cont.([:left, sa, st, nil], merge.(va, vb)) },
-> st { skip.([:right, sa, st, va]) },
stop
)
end
end
end
def zip(rhs)
zip_with(rhs) { |a,b| [a,b] }
end
end
if __FILE__ == $0
FS = 44100.0
TS = 1/FS
def print_action(val)
Action.new { puts val }
end
Stream.step(0, 2 * Math::PI, TS).map { |x| Math.cos(x) }.each { |v| puts(v) }
# Stream.step(0, 3, 1).map { |v| print_action(v) }.inject(Action.noop, &:seq).call
# puts Stream.step(1, 3, 1).inject(1, &:*)
# Stream.step(0, 10, 1).select { |v| v % 2 == 0 }.each { |v| puts v }
# Stream.singleton(42).append(
# Stream.singleton(37)
# ).append(
# Stream.empty
# ).each { |v|
# puts v
# }
# Stream.singleton(2).zip_with(
# Stream.singleton(3),
# &:**
# ).each { |v|
# puts v
# }
# Stream.step(0,10,1).zip(Stream.step(0,10,1)).map { |a,b| a + b }.each { |v| puts v }
# Stream.iterate(0) { |x| x+1 }.zip_with(Stream.repeat(2)) { |a,b| a * b }.each { |v| puts v }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment