ashishwave [email protected] writes:
value of ‘a’ or ‘b’ changes then the value of ‘c’ is updated as the
result of the addition
bye 
Ashish
[email protected].
Half-way done ideas wrt that, inspired by flapjax. No warranty.
$ cat /Users/chris/mess//2006/49/frp.rb
require ‘/Users/chris/projects/blogcode/dynamic.rb’
Thread.abort_on_exception = true
Dynamic.variable :current_calc
class Var
def initialize(value=nil)
@affects = []
@value = value
end
def set!(v)
@value = v
propagate
v
end
def ~
@affects << Dynamic.current_calc if Dynamic.current_calc
@value
end
def propagate
@affects.each { |a| a.call }
end
def map(init=nil, &block)
new = Var.new init
Calc.new { new.set! block.call(~self) }
new
end
def inject(initial, &block)
a = initial
map { |e| a = block.call a, e }
end
def constant(const)
map { const }
end
def hold(initial, &block)
map(initial) { block.call }
end
def filter(&block)
new = Var.new
Calc.new {
this = ~self
if block.call this
new.set! this
end
}
new
end
def merge(other)
new = Var.new
Calc.new { new.set! ~self }
Calc.new { new.set! ~other }
new
end
def calm(window, &block)
last = Time.now
merge(Timer.for(window)).filter {
p [:calm, last, Time.now]
r = (Time.now - last) > window
last = Time.now
r
}
end
end
class Calc < Proc
attr_reader :timers
def initialize(&block)
@timers = {}
super(&block)
Dynamic.let :current_calc => self do
call
end
end
end
class Timer
attr_reader :var
def self.for(period)
if Dynamic.current_calc.nil?
new(period).var
else
Dynamic.current_calc.timers.fetch(period) {
Dynamic.current_calc.timers[period] = new(period)
}.var
end
end
def initialize(period)
@period = period
@var = Var.new Time.now.to_f
Thread.new {
loop {
p "sleeping for #@period"
sleep @period
@var.set! Time.now.to_f
}
}
end
end
x = Var.new 5
Calc.new { p ["at time ", ~Timer.for(0.1), "x is ", ~x] }
Calc.new { p ["x is ", ~x] }
y = x.map { |z| z * 2 }
Calc.new { p [“y is now”, ~y] }
sum = x.inject(0) { |a,e| a + e }
Calc.new { p [“sum is now”, ~sum] }
Timer.for(5).map { p “tick!” }
x.calm(2).map(false) { |v| p “no input for 2 secs!” }
Timer.for(10).merge(x).map { p “either 10s or x” }
x.set! 7
while line = gets.to_i
x.set! line
p ["set to ", ~x]
end