Control flow

## 2.3 Control flow

- Control flow and search
- Asynchronous events
- The yield-resume model
- Summary of EC_resume() arguments

ECLiPSe and a C or C++ main program are like threads running in a single process. Each maintains its state and methods for exchanging data and yielding control to the other thread.
The main method of sending data from C++ to ECLiPSe is by posting goals for it to solve. All posted goals are solved in conjunction with each other, and with any previously posted goals that have succeeded.
Data is passed back by binding logical variables within the goals.
Control is explicit in C++. After posting some goals, the C++ program calls the `EC_resume()` function and these goals are all solved. A return code says whether they were successfully solved or whether a failure occurred.
In ECLiPSe control is normally implicit. Control returns to C++ when all goals have been solved.

        #include        "eclipseclass.h"

        main()
        {
            ec_init();

            /* writeln("hello world"), */
            post_goal(term(EC_functor("writeln",1),"hello world"));
            EC_resume();
            ec_cleanup(0);
        }

The above is an example program that posts a goal and executes it.

### 2.3.1 Control flow and search

Using this model of communication it is possible to construct programs where execution of C++ code and search within the ECLiPSe are interleaved.
If you post a number of goals (of which some are non-deterministic) and resume the ECLiPSe execution and the goals succeed, then control returns to the C++ level. By posting a goal that fails, the ECLiPSe execution will fail back into the previous set of goals and these will succeed with a different solution.

        #include        "eclipseclass.h"

        main()
        {
            ec_init();
            EC_ref Pred;

            post_goal(term(EC_functor("current_built_in",1),Pred));
            while (EC_succeed == EC_resume())
            {
                post_goal(term(EC_functor("writeln",1),Pred));
                post_goal(EC_atom("fail"));
            }
            ec_cleanup(0);
        }

The above example prints all the built ins available in ECLiPSe. When `EC_resume()` returns `EC_succeed` there is a solution to a set of posted goals, and we print out the value of `Pred`. otherwise `EC_resume()` returns `EC_fail` to indicate that no more solutions to any set of posted goals is available.
It is possible also to cut such search. So for example one could modify the example above to only print the 10th answer. Initially one simply fails, but at the tenth solution one cuts further choices. Then one prints the value of 'Pred'.

        #include        "eclipseclass.h"

        main()
        {
            ec_init();
            EC_ref Pred,Choice;
            int i = 0;

            post_goal(term(EC_functor("current_built_in",1),Pred));
            while (EC_succeed == EC_resume(Choice))
            {
                if (i++ == 10)
                {
                    Choice.cut_to();
                    break;
                }
                post_goal(term(EC_atom("fail")));
            }
            post_goal(term(EC_functor("writeln",1),Pred));
            EC_resume():
            ec_cleanup(0);
        }

When `EC_resume()` is called with an `EC_ref` argument, this is for data returned by the `EC_resume()` If the return code is `EC_succeed` The `EC_ref` is set to a choicepoint identifier which can be used for cutting further choices at that point.

### 2.3.2 Asynchronous events

The posting of goals and building of any ECLiPSe terms in general cannot be done asynchronously to the ECLiPSe execution. It has to be done after the `EC_resume()` function has returned.
Sometimes it may be necessary to signal some asynchronous event to ECLiPSe, for example to implement a time-out. To do this one posts a named event to ECLiPSe. At the next synchronous point within the eclipse execution, the handler for that event is invoked.

        /* C++ code, possibly within a signal handler */
        post_event(EC_atom("timeout"));

        /* ECLiPSe code */
        handle_timeout(timeout) :-
            <appropriate action>

        :- set_event_handler(timeout, handle_timeout/1).

### 2.3.3 The yield-resume model

Although implicitly yielding control when a set of goals succeeds or fails is often enough, it is possible to explicitly yield control to the C++ level. This is done with the yield/2 predicate. This yields control to the calling C++ program. The arguments are used for passing data to C++ and from C++.
When yield/2 is called within ECLiPSe code, the `EC_resume()` function returns the value `EC_yield` so one can recognise this case. The data passed out via the first argument of yield/2 can be accessed from C++ via the `EC_ref` argument to `EC_resume()`. The data received in the second argument of yield/2 is either the list of posted goals, or an `EC_word` passed as an input argument to `EC_resume()`.

        yield(out(1,2),InData),

In this example the compound term `out(1,2)` is passed to C++. If we had previously called:

        EC_ref FromEclipse;
        result = EC_resume(FromEclipse);

then `result` would be `EC_yield` and `FromEclipse` would refer to `out(1,2)`. If then we resumed execution with:

        result = EC_resume(EC_atom("ok"),FromEclipse);

then the variable `InData` on the ECLiPSe side would be set to the atom 'ok'.

### 2.3.4 Summary of EC_resume() arguments

`EC_resume()` can be called with two optional arguments. An input argument that is an `EC_word` and an output that is an `EC_ref`.
If the input argument is omitted, input is taken as the list of posted goals. Otherwise the input to ECLiPSe is exactly that argument.
If the output argument is present, its content depends on the value returned by `EC_resume()`. If it returns `EC_succeed` it is the choicepoint identifier. If it returns `EC_yield` It is the first argument to the yield/2 goal. If it returns `EC_fail` it is not modified.