Faliure-based (goal-directed) control instead of boolean-based control
I think that boolean-based control has been one of the most expensive mistakes of humanity in computing. Far more natural both for humans and computers is to express execution control in terms of success and failure. In a concatenative language, it'd look like this:
All functions (except explicit failure) can succeed in which case the next function is evaluated next. Some functions can also fail, in which case execution continues with the failure handler. Registering the failure handler also marks both stacks; upon failure, stack pointers are reset to their marked point and the outer (previous) failure handler (and the corresponding stack mark) becomes current, in case the handler itself fails. If you have algebraic effects, then failure is simply one of them. If you don't, you can annotate the output stack effect of potentially failing functions with "maybe".
This allows for a few very practical constructs:
A function that is its own failure handler is a "generator". It is very convenient to implement backtracking searches with putting various filters after such generators.
Disjunction (denoted by
OR ) takes two functions with the same output effect as arguments, sets the second one (subject) as the failure handler while executing the first one (predicate). If the predicate succeeds, the failure handler is restored. If both functions are generators, the disjunction generates the values of the first one followed by the values of the second one.
WHILE would also take two functions of the type
( a -- b ) and
( b -- a ), predicate and subject. The two are executed in a tail-recursive loop one after the other. If the predicate fails, the subject is not executed and the
WHILE combinator succeeds. If the subject fails, the
WHILE combinator fails also.
I'm not entirely sure what you're proposing.
The current line of thinking is that failure will be represented by a
Result type, as in Haskell and Elm. Additionally, one might 'panic', but this cannot be caught and would bring the entire program to a halt. As such, a function call in Play cannot really fail.
But what you suggest does sound interesting. Are you able to explain it differently? How would it look like in code?