Hi Dan,
> On 21 Jan 2019, at 11:27, Dan <
gros...@gmail.com> wrote:
>
> Hi Paolo,
Paulo, not Paolo. I'm Portuguese, not Italian; although I do love pasta :-)
> Indeed i am calling e_ground/2. thank you for catching the typo in the form posting.
>
> The second argument carries an atom that indicates the error; such as the second_arg was not ground, as expected; although not all e_preds wrapper require a second argument -- sometimes the reason for failure is context-free.
>
> Once i have those wrappers, higher level predicates won't fail but either return the expected result or ereturn the error in a pair, such as (error, arg2_not_ground) ..
You're describing expected terms. Note that global variables, which you are trying to base your implementation on, are neither thread nor module friendly.
> to enable continued flow at the caller site i added a check_error predicate such as below: When the check_error encounters a pair with an error as its first arg, then it will fail, and restores at the outer level the "inner" error that was captured. effectively continuing the error flow control
> ...
Consider the following example code (requires the Logtalk current git version due to the new expected::from_goal/4 predicate):
:- object(cascade).
:- public(process_image/2).
:- uses(random, [maybe/1]).
process_image(Image, Final) :-
expected::of_expected(Image, Final0),
crop_to_cat(Final0, Final1),
add_bow_tie(Final1, Final2),
make_eyes_sparkle(Final2, Final3),
make_smaller(Final3, Final4),
add_rainbow(Final4, Final5),
expected(Final5)::or_else_throw(Final).
crop_to_cat(In, Out) :-
expected(In)::flat_map(
[Value,Ref]>>(expected::from_goal(maybe(0.9), cropped(Value), missing_cat, Ref)),
Out
).
add_bow_tie(In, Out) :-
expected(In)::flat_map(
[Value,Ref]>>(expected::from_goal(maybe(0.9), with_bow_tie(Value), bow_tie_failure, Ref)),
Out
).
make_eyes_sparkle(In, Out) :-
expected(In)::flat_map(
[Value,Ref]>>(expected::from_goal(maybe(0.9), sparkling_eyes(Value), eyes_closed, Ref)),
Out
).
make_smaller(In, Out) :-
expected(In)::flat_map(
[Value,Ref]>>(expected::from_goal(maybe(0.9), smaller(Value), wants_to_grow, Ref)),
Out
).
add_rainbow(In, Out) :-
expected(In)::flat_map(
[Value,Ref]>>(expected::from_goal(maybe(0.9), with_rainbow(Value), sunny_day, Ref)),
Out
).
:- end_object.
You may recognize the example from the URL I mentioned earlier:
https://blog.tartanllama.xyz/optional-expected/
It also should be noted that threading "state" screams DCGs :-) In this case, the "state" being threaded is the expected terms. The definitions of the individual filter predicates (crop_to_cat/2, ...) basically either cause an error (missing_cat, bow_tie_failure, ...) or apply the filter, based on a call to the random::maybe(0.9) predicate which succeeds with probability 0.9. The last call, expected/1::or_else_throw/1, looks into the expected term reference and either returns the term if expected or throws the exception if unexpected. Trying the main predicate illustrates the behavior you're looking for:
?- {library(random_loader), library(expected_loader)}.
...
?- {cascade}.
...
?- cascade::process_image(image, Final).
Final = with_rainbow(smaller(sparkling_eyes(with_bow_tie(cropped(image))))).
?- cascade::process_image(image, Final).
ERROR: Unhandled exception: missing_cat
?- cascade::process_image(image, Final).
Final = with_rainbow(smaller(sparkling_eyes(with_bow_tie(cropped(image))))).
?- cascade::process_image(image, Final).
ERROR: Unhandled exception: eyes_closed
?- cascade::process_image(image, Final).
Final = with_rainbow(smaller(sparkling_eyes(with_bow_tie(cropped(image))))).
?- cascade::process_image(image, Final).
ERROR: Unhandled exception: missing_cat
?- cascade::process_image(image, Final).
Final = with_rainbow(smaller(sparkling_eyes(with_bow_tie(cropped(image))))).
?- cascade::process_image(image, Final).
ERROR: Unhandled exception: sunny_day
?- ...
This solution requires the filter predicates to accept and return expected term references. An alternative could be to have these predicates worked with reified results (e.g. true(Result), fail, error(Error)). Both solutions are fully portable and don't use non-logical nastiness such as global variables :-)
Cheers,
Paulo