bloom-lang / bud

Prototype Bud runtime (Bloom Under Development)
http://bloom-lang.net
Other
854 stars 60 forks source link

conditionals around rules #207

Open jhellerstein opened 13 years ago

jhellerstein commented 13 years ago

Or perhaps nested rules?

From the Syntax-Wishlist wiki:

Currently we achieve this by mutually-exclusive predicates buried inside multiple rule bodies. This example has two rules. The 1st rule has two cases within a single rule, which works because they share a head. The second rule happens to be the "else" of the first rule, with a different head.

    # we can respond locally for keys that are here or at our successor
    find_resp <~ find_event do |e|
      start = nil    
      # if at successor:
      if at_successor(e.key)   
        if e.pred_or_succ == 'pred'
          start = me.first.start; addr = ip_port
        elsif e.pred_or_succ == 'succ' and finger[[0]] and not finger[[0]].succ.nil?
          start = finger[[0]].succ; addr = finger[[0]].succ_addr
        end
      # else if local:
      elsif at_local(e.key)
        if e.pred_or_succ == 'pred'
          start = me.first.pred_id; addr = me.first.pred_addr
        elsif e.pred_or_succ == 'succ'
          start = me.first.start; addr = ip_port
        end
      end
      [e.from, e.key, e.pred_or_succ, start, addr] unless start.nil?
    end

    # for keys that are not at successor, forward to closest finger   
    find_req <~ (find_event * closest).combos(:key => :key) do |e, c| 
      [c.succ_addr, e.key, e.from, e.pred_or_succ] unless at_successor(e.key) or at_local(e.key)
    end
jhellerstein commented 12 years ago

A pattern using the "with" construct introduced in 2f9c6e580b4ff065ea7d helps a bit, by forcing all branches of the conditional to appear together. Suppose we have:

yay <= foo { |t| t if ruby_predicate(t) } 
boo <= foo { |t| t unless ruby_predicate(t) }

That's readable, but there's the reasonable concern that the two rules could get separated in the code and still mean the same thing.

We could instead write

with :outcome <= foo { |t| [t, ruby_predicate(t)] }, begin
  yay <= outcome { |o| o[0] if o[1] }
  boo <= outcome { |o| o[0] unless o[1] }
end

Here, the two rules have to stay together inside the scope of with.

It'd still be nice to have more syntactic sugar.