tags:

views:

28

answers:

2

I'm reading about visual programming languages these days. So I've thought up two "paradigms". In both of them, you have one start point, and several end points.

Now, you could either begin at the start point or move in reverse from the end points (the order of end points is known).

Beginning from the start point feels weird, because you can have "splits" in the data flow. Say, if I have an interger, and this integer is needed by two functions simultaenously. Bad. I don't want to get into concurrent coding. Atleast not yet. Or should I?

Beginning at the end points feels much better. You start at the first end point. Check whatever is needed, and evaluate that. I believe this is the lazy evaluation. But the problem comes when you have multiple inputs. How do you decide the order in which to evaluate the inputs?

Can you point me to some articles/papers/something on the internet. Or mabye tell me a few keywords to look for?

+1  A: 

If I get what you mean, using the same integer in two functions, is exactly that: you just use it twice, no need to bring concurrency in. If the 'implementation' you were thinking about destroyed input values, you could take a copy before using it.

int i = 2;
int j = fun1(i);
int k = fun2(i);
int res = fun3(j, k);

would become:

      i = 2[A]
        |
      Clone[B]
       / \
      /   \
     /     \
   i_1      i_2
    |        |
   fun1[C]  fun2[D]
    |        |
    j        k
     \      /
      \    /
       \  /
       fun3[E]
        |
       res

But there's no need of concurrency in order to evaluate the graph. You can just evaluate 'parallel' branches left to right (as indicated by the A-B-C-... labelling - see also here).

Top-down (aka from start to end), left-to-right feels more natural than bottom-up, provided bottom-up actually has a well defined meaning. Regarding the latter point, assuming you do have results for the program, you can't always compute the inputs: think about what happens when funXXX are not injective (for example fun1(x) = x*x) and thus not invertible.

I hope I'm not completely misinterpreting your train of thought.

Mau
By the bottom-up approach I meant I know the very last functions that need to be executed and their order. Like, I need to execute a printf first, then an fread, and finally draw some graphic. All these require additional parameters (which are produced by other functions). Going through topological ordering, it seems this is what I wanted!!
Utkarsh Sinha
+1  A: 

Moving forward, what you want is the topological sort of your dependency graph - that is, an order in which to execute nodes such that you never execute a node before its dependencies. This assumes, naturally, that there are no cycles in your graph.

Moving backwards, what you're doing is recursively resolving the graph. Starting with the end node, for each dependency that is not yet calculated, you recursively invoke the procedure on that node, until all input values are evaluated. This has the advantage that you never process nodes that aren't required by a particular end state.

Which of the two approaches is best depends somewhat on what precisely you're doing.

Nick Johnson