Created
September 3, 2015 01:51
-
-
Save jp-diegidio/2914cac8b5cfb2b6a95e to your computer and use it in GitHub Desktop.
Answer Sources in Prolog (SWI) - Preview
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
/* | |
Answer Sources in Prolog (SWI) - Preview | |
Answer Sources: Extensions | |
Copyright (c) 2015 Julio P. Di Egidio | |
http://julio.diegidio.name/ | |
All rights reserved. | |
Answer Sources: Extensions | |
-------------------------- | |
Extends answer sources with few utilities and the basic combinators. | |
NOTE: | |
- Predicates in this module do not validate their input. | |
- Access to predicates in this module is not sychronised. | |
TODO: | |
*/ | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%(SWI 7.2.3) | |
:- module(nan_kernel_ex, | |
[ using_source/4, % (@, @, -, :) is nondet | |
using_sources/4, % (:, +, -, :) is nondet | |
source_first/2, % (+, ?) is semidet | |
source_enum/2, % (+, ?) is nondet | |
append_sources/2, % (+, -) is det | |
compose_sources/2 % (+, -) is det | |
]). | |
:- reexport('Nan.Kernel'). | |
:- use_module(library(apply)). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%! using_source (@AnsPatt, @Goal, -Source, :GUsing) is nondet | |
%! using_sources (:PComb, +Sources, -Source, :GUsing) is nondet | |
/* | |
?- using_source(s1, sleep(2), _S1, | |
using_source(s2, sleep(2), _S2, | |
using_source(s3, sleep(2), _S3, | |
using_sources(compose_sources, [_S1, _S2, _S3], _S, | |
( time(source_next(_S, answer(_, the([A1, A2, A3])))) | |
))))). | |
% 546 inferences, 0.000 CPU in 2.000 seconds (0% CPU, Infinite Lips) | |
A1 = answer(last, the(s1)), | |
A2 = answer(last, the(s2)), | |
A3 = answer(last, the(s3)). | |
*/ | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
:- meta_predicate | |
using_source(+, 0, -, 0). | |
using_source(AnsP, G, Src, GU) :- | |
setup_call_cleanup( | |
source_open(AnsP, G, Src), | |
GU, | |
source_close(Src) | |
). | |
:- meta_predicate | |
using_sources(2, +, -, 0). | |
using_sources(PC, Srcs, Src, GU) :- | |
setup_call_cleanup( | |
call(PC, Srcs, Src), | |
GU, | |
source_close(Src) | |
). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%! source_first (+Source, -Answer) is det | |
%! source_first (+Source, ?Answer) is semidet | |
%! | |
%! Gets the first answer from a given source. | |
%! Resets the source Source, gets the first answer from it, and | |
%! unifies the answer with Answer. | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
source_first(Src, Ans) :- | |
source_reset(Src), | |
source_next(Src, Ans). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%! source_enum (+Source, -Answer) is multi | |
%! source_enum (+Source, ?Answer) is nondet | |
%! | |
%! Enumerates answers from a given source. | |
%! Gets on backtracking answers from the source Source, and unifies | |
%! each answer with Answer. | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
source_enum(Src, Ans) :- | |
source_next(Src, Ans0), | |
source_enum__sel(Src, Ans0, Ans). | |
source_enum__sel(_, Ans0, Ans) :- | |
Ans \= Ans0, !, fail. | |
source_enum__sel(_, Ans0, Ans0). | |
source_enum__sel(Src, _, Ans) :- | |
source_enum(Src, Ans). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%! append_sources (+Sources, -Source) is det | |
%! | |
%! Append combinator over a list of sources. | |
%! Creates a new source Source that combines answers from the sources | |
%! listed in Sources. Source gets an answer from the first source in | |
%! Sources that is not closed, defaulting to failure when all the | |
%! sources are closed (or the list is empty). Resettings Source | |
%! resets all Sources (that are not closed). | |
/* | |
?- source_open(I, between(1, 2, I), S1), | |
source_open(I, between(3, 4, I), S2). | |
S1 = source(t0, 156), | |
S2 = source(t0, 157). | |
?- append_sources([$S1, $S2], S). | |
S = source(t1, 158). | |
?- source_close($S1). | |
true. | |
?- findall(A, source_enum($S, answer(_, the(A))), As). | |
As = [3, 4]. | |
?- findall(A, source_enum($S, answer(_, the(A))), As). | |
As = []. | |
?- source_reset($S). | |
true. | |
?- findall(A, source_enum($S, answer(_, the(A))), As). | |
As = [3, 4]. | |
?- source_close($S2), | |
source_reset($S). | |
true. | |
?- findall(A, source_enum($S, answer(_, the(A))), As). | |
As = []. | |
?- source_close($S). | |
true. | |
*/ | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
append_sources(Srcs, Src) :- | |
PReset = append_s__reset, | |
PNext = append_s__next, | |
maplist(append_s__ts0__do, Srcs, Ts0), | |
source_open(Srcs, Ts0, PReset, PNext, Src). | |
append_s__reset(Srcs, Ts0, Ts1) :- | |
maplist(append_s__reset__do, Srcs, Ts0, Ts1). | |
append_s__next(Srcs, Ts0, Ts1, Ans) :- | |
foldl(append_s__next__do, Srcs, Ts0, Ts1, Ans, Ans), | |
(var(Ans) -> Ans = answer(fail, no) ; true). | |
append_s__ts0__do(_, t). | |
append_s__reset__do(Src, t, t) :- | |
source_exists(Src, true), !, | |
source_reset(Src). | |
append_s__reset__do(_, _, f). | |
append_s__next__do(_, T0, T0, Ans, Ans) :- | |
nonvar(Ans), !. | |
append_s__next__do(Src, t, t, Ans, Ans) :- | |
source_exists(Src, true), !, | |
source_next(Src, Ans). | |
append_s__next__do(_, _, f, Ans, Ans). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%! compose_sources (+Sources, -Source) is det | |
%! | |
%! Compose combinator over a list of sources. | |
%! Creates a new source Source that combines answers from the sources | |
%! listed in Sources. In parallel, Source gets one answer from every | |
%! one of Sources (if any source is closed, defaults to failure), and | |
%! returns a list of the answers so collected. Resettings Source | |
%! resets all Sources (that are not closed). | |
/* | |
?- source_open(I, between(1, 2, I), S1), | |
source_open(I, between(3, 4, I), S2). | |
S1 = source(t0, 39), | |
S2 = source(t0, 40). | |
?- compose_sources([$S1, $S2], S). | |
S = source(t1, 41). | |
?- source_enum($S, answer(_, the(As))). | |
As = [answer(more, the(1)), answer(more, the(3))] ; | |
As = [answer(last, the(2)), answer(last, the(4))] ; | |
As = [answer(fail, no), answer(fail, no)] ; | |
As = [answer(fail, no), answer(fail, no)] . | |
?- source_reset($S). | |
true. | |
?- source_enum($S, answer(_, the(As))). | |
As = [answer(more, the(1)), answer(more, the(3))] . | |
?- source_reset($S1). | |
true. | |
?- source_enum($S, answer(_, the(As))). | |
As = [answer(more, the(1)), answer(last, the(4))] ; | |
As = [answer(last, the(2)), answer(fail, no)] ; | |
As = [answer(fail, no), answer(fail, no)] . | |
?- source_close($S1), source_reset($S). | |
true. | |
?- source_enum($S, answer(_, the(As))). | |
As = [answer(fail, no), answer(more, the(3))] ; | |
As = [answer(fail, no), answer(last, the(4))] ; | |
As = [answer(fail, no), answer(fail, no)] . | |
?- source_close($S2), source_reset($S). | |
true. | |
?- source_enum($S, answer(_, the(As))). | |
As = [answer(fail, no), answer(fail, no)] . | |
?- source_close($S). | |
true. | |
*/ | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
compose_sources(Srcs, Src) :- | |
PReset = compose_s__reset, | |
PNext = compose_s__next, | |
maplist(compose_s__ts0__do, Srcs, Ts0), | |
source_open(Srcs, Ts0, PReset, PNext, Src). | |
compose_s__reset(Srcs, Ts0, Ts1) :- | |
maplist(compose_s__reset__do, Srcs, Ts0, Ts1). | |
compose_s__next(Srcs, Ts0, Ts1, answer(more, the(Anss))) :- | |
maplist(compose_s__next_b__do, Srcs, Ts0, Ts01), | |
maplist(compose_s__next_e__do, Srcs, Ts01, Ts1, Anss). | |
compose_s__ts0__do(_, t). | |
compose_s__reset__do(Src, t, t) :- | |
source_exists(Src, true), !, | |
source_reset(Src). | |
compose_s__reset__do(_, _, f). | |
compose_s__next_b__do(Src, t, t) :- | |
source_exists(Src, true), !, | |
source_next_begin(Src). | |
compose_s__next_b__do(_, _, f). | |
compose_s__next_e__do(Src, t, t, Ans) :- | |
source_exists(Src, true), !, | |
source_next_end(Src, Ans). | |
compose_s__next_e__do(_, _, f, answer(fail, no)). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
/* | |
Answer Sources in Prolog (SWI) - Preview | |
Answer Sources | |
Copyright (c) 2015 Julio P. Di Egidio | |
http://julio.diegidio.name/ | |
All rights reserved. | |
Answer Sources | |
-------------- | |
Answer sources can be seen as generalized iterators, allowing a given | |
program to control answer production in another. Each answer source | |
works as a separate Prolog interpreter... | |
Multithreading => parallelism... | |
NOTE: | |
- Predicates in this module do not validate their input. | |
- Access to predicates in this module is not sychronised. | |
TODO: | |
- Redesign in terms of a thread-pool. | |
- Rewrite to get rid of the global cuts. | |
- Abstract away cross-cutting concerns: | |
(validation?), exceptions, logging, database, id/key gen. | |
- Remove logging calls with nan_kernel_debug(false). | |
Main SWI specifics: threads, message queues, global cuts. | |
*/ | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%(SWI 7.2.3) | |
:- module(nan_kernel, | |
[ source_exists/2, % (+, ?) is semidet | |
source_open/5, % (+, +, @, @, -) is det | |
source_open/3, % (@, @, -) is det | |
source_close/1, % (+) is det | |
source_reset/1, % (+) is det | |
source_next/2, % (+, ?) is semidet | |
source_next_begin/1, % (+) is det | |
source_next_end/2 % (+, ?) is semidet | |
]). | |
:- use_module(library(debug)). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%! source_exists (+Source, ?Exists) is semidet | |
%! source_open (+Sources, +State0, @PReset, @PNext, -Source) is det | |
%! source_open (@AnsPatt, @Goal, -Source) is det | |
%! source_close (+Source) is det | |
%! source_reset (+Source) is det | |
%! source_next (+Source, ?Answer) is semidet | |
%! source_next_begin (+Source) is det | |
%! source_next_end (+Source, ?Answer) is semidet | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
source_exists(Src, Exists) :- | |
source_sid(Src, Sid), | |
source_db_exists_(Sid, Exists). | |
:- meta_predicate | |
source_open(+, +, 3, 4, -). | |
source_open(Srcs, T0, PR, PN, Src) :- | |
source_open_(Srcs, T0, PR, PN, Sid), | |
source_sid(Src, Sid). | |
:- meta_predicate | |
source_open(+, 0, -). | |
source_open(AnsP, G, Src) :- | |
source_open_(AnsP, G, Sid), | |
source_sid(Src, Sid). | |
source_close(Src) :- | |
source_sid(Src, Sid), | |
source_close_(Sid). | |
source_reset(Src) :- | |
source_sid(Src, Sid), | |
source_reset_(Sid). | |
source_next(Src, Ans) :- | |
source_sid(Src, Sid), | |
source_next_(Sid, Ans). | |
source_next_begin(Src) :- | |
source_sid(Src, Sid), | |
source_next_begin_(Sid). | |
source_next_end(Src, Ans) :- | |
source_sid(Src, Sid), | |
source_next_end_(Sid, Ans). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% source_open_ (+Srcs, +T0, @PR, @PN, -Sid) is det | |
% source_open_ (@AnsP, @G, -Sid) is det | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
:- meta_predicate | |
source_open_(+, +, 3, 4, -). | |
source_open_(Srcs, T0, PR, PN, Sid) :- | |
source_new_sid_(t1, Sid), | |
source_log_act_( | |
( copy_term([PR, PN], [PR1, PN1]), | |
source_db_add_(Sid, t1(Srcs, T0, PR1, PN1)) | |
), Sid, 'OPEN' | |
). | |
:- meta_predicate | |
source_open_(+, 0, -). | |
source_open_(AnsP, G, Sid) :- | |
source_new_sid_(t0, Sid), | |
source_log_act_( | |
( source_open__do(Sid, AnsP, G) | |
), Sid, 'OPEN' | |
). | |
:- meta_predicate | |
source_open__do(+, +, 0). | |
source_open__do(Sid, AnsP, G) :- | |
source_open__pre(Sid, AnsP, G, [Pid, Tid, GExec]), | |
source_open__all(Sid, Pid, Tid, GExec, ErrA1), | |
( source_err_(ErrA1, true, _) | |
-> source_open__abort(Sid, ErrA2) | |
; true | |
), | |
source_throw_([ErrA1, ErrA2]), | |
source_log_(Sid, 'OPEN', 'OPENED'). | |
:- meta_predicate | |
source_open__pre(+, +, 0, -). | |
source_open__pre(Sid, AnsP, G, [Pid, Tid, GExec]) :- | |
copy_term([AnsP, G], [AnsP1, G1]), | |
source_sid_key(Sid, Tid), | |
atom_concat(Tid, '_p', Pid), | |
GExec = source_exec(Sid, AnsP1, G1). | |
:- meta_predicate | |
source_open__all(+, +, +, 0, -). | |
source_open__all(Sid, Pid, Tid, GExec, ErrA) :- | |
source_catch_( | |
( source_db_add_(Sid, t0(Pid, Tid)), | |
message_queue_create(_, [alias(Pid)]), | |
thread_create(GExec, _, [alias(Tid)]) | |
), ErrA | |
). | |
source_open__abort(Sid, ErrA) :- | |
source_catch_( | |
source_close_(Sid), ErrA | |
). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% source_close_ (+Sid) is det | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
source_close_(Sid) :- | |
source_sid_type(Sid, t1), !, | |
source_log_act_( | |
( source_db_del_(Sid) | |
), Sid, 'CLOSE' | |
). | |
source_close_(Sid) :- | |
source_db_get_(Sid, t0(Pid, Tid)), | |
source_log_act_( | |
( source_close__do(Sid, Pid, Tid) | |
), Sid, 'CLOSE' | |
). | |
source_close__do(Sid, Pid, Tid) :- | |
source_close__thread(Sid, Tid, StaT, ErrA1), | |
source_close__queue(Pid, ErrA2), | |
source_close__db(Sid, ErrA3), | |
source_throw_([ErrA1, ErrA2, ErrA3]), | |
source_log_(Sid, 'CLOSE', '~|CLOSED~8+(StaT = ~w)', [StaT]). | |
source_close__thread(Sid, Tid, StaT, ErrA) :- | |
source_catch_( | |
( ( thread_property(Tid, status(running)) | |
-> source_msg_send_(Sid, 'CLOSE', Tid, close) | |
; true | |
), thread_join(Tid, StaT) | |
), ErrA | |
). | |
source_close__queue(Qid, ErrA) :- | |
source_catch_( | |
message_queue_destroy(Qid), ErrA | |
). | |
source_close__db(Sid, ErrA) :- | |
source_catch_( | |
source_db_del_(Sid), ErrA | |
). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% source_reset_ (+Sid) is det | |
% source_next_ (+Sid, ?Ans) is semidet | |
% source_next_begin_ (+Sid) is det | |
% source_next_end_ (+Sid, ?Ans) is semidet | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
source_reset_(Sid) :- | |
source_sid_type(Sid, t1), !, | |
source_db_get_(Sid, t1(Srcs, T0, PR, _)), | |
source_log_act_( | |
( source_reset__do(Srcs, PR, T0, T1), | |
source_next__t1_state(Sid, T1) | |
), Sid, 'RESET' | |
). | |
source_reset_(Sid) :- | |
source_db_get_(Sid, t0(_, Tid)), | |
source_log_act_( | |
( source_reset__do(Sid, 'RESET', Tid) | |
), Sid, 'RESET' | |
). | |
source_next_(Sid, Ans) :- | |
source_sid_type(Sid, t1), !, | |
source_db_get_(Sid, t1(Srcs, T0, _, PN)), | |
source_log_act_( | |
( source_next__do(Srcs, PN, T0, T1, Ans), | |
source_next__t1_state(Sid, T1) | |
), Sid, 'NEXT' | |
). | |
source_next_(Sid, Ans) :- | |
source_db_get_(Sid, t0(Pid, Tid)), | |
source_log_act_( | |
( source_next_begin__do(Sid, 'NEXT', Tid), | |
source_next_end__do(Sid, 'NEXT', Pid, Ans) | |
), Sid, 'NEXT' | |
). | |
source_next_begin_(Sid) :- | |
source_sid_type(Sid, t1), !, | |
source_log_act_( | |
( true | |
), Sid, 'NEXT_B' | |
). | |
source_next_begin_(Sid) :- | |
source_db_get_(Sid, t0(_, Tid)), | |
source_log_act_( | |
( source_next_begin__do(Sid, 'NEXT_B', Tid) | |
), Sid, 'NEXT_B' | |
). | |
source_next_end_(Sid, Ans) :- | |
source_sid_type(Sid, t1), !, | |
source_db_get_(Sid, t1(Srcs, T0, _, PN)), | |
source_log_act_( | |
( source_next__do(Srcs, PN, T0, T1, Ans), | |
source_next__t1_state(Sid, T1) | |
), Sid, 'NEXT_E' | |
). | |
source_next_end_(Sid, Ans) :- | |
source_db_get_(Sid, t0(Pid, _)), | |
source_log_act_( | |
( source_next_end__do(Sid, 'NEXT_E', Pid, Ans) | |
), Sid, 'NEXT_E' | |
). | |
source_next__t1_state(Sid, T1) :- | |
source_db_get_(Sid, t1(Srcs, T0, PR, PN)), | |
( T1 \== T0 | |
-> source_db_del_(Sid), | |
source_db_add_(Sid, t1(Srcs, T1, PR, PN)) | |
; true | |
). | |
:- meta_predicate | |
source_reset__do(+, 3, +, -). | |
source_reset__do(Srcs, PR, T0, T1) :- | |
call(PR, Srcs, T0, T1), !. | |
:- meta_predicate | |
source_next__do(+, 4, +, -, ?). | |
source_next__do(Srcs, PN, T0, T1, Ans) :- | |
call(PN, Srcs, T0, T1, Ans1), !, Ans = Ans1. | |
source_reset__do(Sid, Act, Tid) :- | |
source_msg_send_(Sid, Act, Tid, reset). | |
source_next_begin__do(Sid, Act, Tid) :- | |
source_msg_send_(Sid, Act, Tid, next). | |
source_next_end__do(Sid, Act, Pid, Ans) :- | |
source_msg_recv_(Sid, Act, Pid, Msg), | |
( Msg = fail -> Ans = answer(fail, no) | |
; Msg = last(AnsP) -> Ans = answer(last, the(AnsP)) | |
; Msg = more(AnsP) -> Ans = answer(more, the(AnsP)) | |
; Msg = except(Err) -> throw(Err) | |
; throw(source_error(unknown_message(data, Sid, Msg), _)) | |
). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%! source_exec (+Sid, ?AnsP, :G) is det | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
:- public | |
source_exec/3. | |
:- meta_predicate | |
source_exec(+, ?, 0). | |
source_exec(Sid, AnsP, G) :- | |
source_db_get_(Sid, t0(Pid, Tid)), | |
source_log_act_( | |
call_cleanup( | |
source_exec__loop_0(Sid, Pid, Tid, AnsP, G), | |
exception(Err), | |
source_msg_send_(Sid, 'EXEC', Pid, except(Err)) | |
), Sid, 'EXEC' | |
). | |
:- meta_predicate | |
source_exec__loop_0(+, +, +, ?, 0). | |
source_exec__loop_0(Sid, Pid, Tid, AnsP, G) :- | |
repeat, | |
source_msg_recv_(Sid, 'EXEC', Tid, Msg), | |
( Msg == reset -> fail | |
; Msg == close -> ! | |
; Msg == next -> !, | |
source_exec__loop_1(Sid, Pid, Tid, AnsP, G) | |
; throw(source_error(unknown_message(ctrl, Sid, Msg), _)) | |
). | |
:- meta_predicate | |
source_exec__loop_1(+, +, +, ?, 0). | |
source_exec__loop_1(Sid, Pid, Tid, AnsP, G) :- | |
prolog_current_choice(Loop1), | |
repeat, | |
prolog_current_choice(Loop2), | |
source_exec__loop_2(Sid, Pid, AnsP, G), | |
source_exec__recv(Sid, Tid, Loop1, Loop2). | |
:- meta_predicate | |
source_exec__loop_2(+, +, ?, 0). | |
source_exec__loop_2(Sid, Pid, AnsP, G) :- | |
( call_cleanup(G, Det = true), | |
( Det == true | |
-> source_msg_send_(Sid, 'EXEC', Pid, last(AnsP)) | |
; source_msg_send_(Sid, 'EXEC', Pid, more(AnsP)) | |
), | |
source_log_(Sid, 'EXEC', '~|CALLED~8+(Det = ~w)', [Det]) | |
; repeat, | |
source_msg_send_(Sid, 'EXEC', Pid, fail) | |
). | |
source_exec__recv(Sid, Tid, Loop1, Loop2) :- | |
source_msg_recv_(Sid, 'EXEC', Tid, Msg), | |
( Msg == next -> fail | |
; Msg == close -> prolog_cut_to(Loop1) | |
; Msg == reset -> prolog_cut_to(Loop2), | |
source_exec__recv(Sid, Tid, Loop1, Loop2) | |
; throw(source_error(unknown_message(ctrl, Sid, Msg), _)) | |
). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% source_msg_send_ (+Sid, +Act, +Qid, +Msg) is det | |
% source_msg_recv_ (+Sid, +Act, +Qid, -Msg) is det | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
source_msg_send_(Sid, Act, Qid, Msg) :- | |
thread_send_message(Qid, Msg), | |
source_log_msg_(Sid, Act, '>>', Msg). | |
source_msg_recv_(Sid, Act, Qid, Msg) :- | |
thread_get_message(Qid, Msg), | |
source_log_msg_(Sid, Act, '<<', Msg). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% source_catch_ (:GAct, -ErrA) is det | |
% source_throw_ (+ErrAs) is det | |
% source_err_ (+ErrA, -HasErr, -Err) is det | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
:- meta_predicate | |
source_catch_(0, -). | |
source_catch_(GAct, ErrA) :- | |
catch( | |
( call(GAct), | |
HasErr = false | |
), | |
Err, HasErr = true | |
), | |
source_err_(ErrA, HasErr, Err). | |
source_throw_(ErrAs) :- | |
source_throw___loop(ErrAs, Errs), | |
( Errs = [] -> true | |
; Errs = [Err] -> throw(Err) | |
; throw(source_error(many_errors, Errs)) | |
). | |
source_throw___loop([], []). | |
source_throw___loop([ErrA| ErrAs], Errs) :- | |
source_err_(ErrA, HasErr, Err), | |
( HasErr == true | |
-> Errs = [Err| Errs1] | |
; Errs = Errs1 | |
), | |
source_throw___loop(ErrAs, Errs1). | |
source_err_(ErrA, HasErr, Err) :- | |
ErrA = err(HasErr, Err). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% source_log_act_ (:GAct, +Sid, +Act) is det | |
% source_log_msg_ (+Sid, +Act, +Dir, +QMsg) is det | |
% source_log_ (+Sid, +Act, +Msg1) is det | |
% source_log_ (+Sid, +Act, +Fmt1, +Args1) is det | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
:- meta_predicate | |
source_log_act_(0, +, +). | |
source_log_act_(GAct, Sid, Act) :- | |
setup_call_cleanup( | |
source_log_(Sid, Act, 'Start...'), | |
GAct, | |
source_log_(Sid, Act, 'Done.') | |
). | |
source_log_msg_(Sid, Act, Dir, QMsg) :- | |
( debugging(nan_kernel) | |
-> ( Act == 'EXEC' | |
-> (Dir == '>>' -> Typ = data ; Typ = ctrl) | |
; (Dir == '>>' -> Typ = ctrl ; Typ = data) | |
), | |
Args = [Dir, Typ, QMsg], | |
source_log__do(Sid, Act, '~|--~a--~8+(~a) ~w', Args) | |
; true | |
). | |
source_log_(Sid, Act, Msg1) :- | |
( debugging(nan_kernel) | |
-> source_log__do(Sid, Act, Msg1, []) | |
; true | |
). | |
source_log_(Sid, Act, Fmt1, Args1) :- | |
( debugging(nan_kernel) | |
-> source_log__do(Sid, Act, Fmt1, Args1) | |
; true | |
). | |
source_log__do(Sid, Act, Fmt1, Args1) :- | |
get_time(Tm), | |
Tm1 is floor(float_fractional_part(Tm / 100) * 100_000), | |
format(atom(TM), '~3d', [Tm1]), | |
Term = nan_kernel__source(Sid, Act, TM, Fmt1, Args1), | |
print_message(informational, Term). | |
:- multifile | |
prolog:message//1. | |
prolog:message(nan_kernel__source(Sid, Act, TM, Fmt1, Args1)) --> | |
{ source_sid_sel_(_, TNum, Id, Sid), | |
format(atom(Msg1), Fmt1, Args1), | |
Args = [TM, TNum, Id, Act, Msg1] | |
}, ['~a : source(t~d, ~d) : ~|~w~6+ : ~a'-Args]. | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% source_db_exists_ (+Sid, ?Exists) is semidet | |
%! source_db_gen (?Sid, ?Term) is nondet | |
% source_db_add_ (+Sid, +Term) is det | |
% source_db_get_ (+Sid, -Term) is det | |
% source_db_del_ (+Sid) is det | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
source_db_exists_(Sid, Exists) :- | |
source_sid_key(Sid, Key), | |
( recorded(Key, _) | |
-> Exists = true | |
; Exists = false | |
). | |
:- public | |
source_db_gen/2. | |
source_db_gen(Sid, Term) :- | |
recorded(Key, Term), | |
source_sid_key(Sid, Key). | |
source_db_add_(Sid, Term) :- | |
source_db__val(has_not, Sid, Key), | |
recordz(Key, Term). | |
source_db_get_(Sid, Term) :- | |
source_db__val(has, Sid, _, Term, _). | |
source_db_del_(Sid) :- | |
source_db__val(has, Sid, _, _, Ref), | |
erase(Ref). | |
source_db__val(has_not, Sid, Key) :- | |
source_sid_key(Sid, Key), | |
( \+ recorded(Key, _) | |
-> true | |
; throw(source_error(record_exists_already(Sid, Key), _)) | |
). | |
source_db__val(has, Sid, Key, Term, Ref) :- | |
source_sid_key(Sid, Key), | |
( recorded(Key, Term, Ref) | |
-> true | |
; throw(source_error(record_does_not_exist(Sid, Key), _)) | |
). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%! source_sid (+Source, -Sid) is semidet | |
%! source_sid (-Source, +Sid) is det | |
%! source_sid_type (+Sid, -Type) is det | |
%! source_sid_key (+Sid, -Key) is det | |
%! source_sid_key (-Sid, +Key) is det | |
% source_sid_sel_ (+Type, +TNum, +Id, -Sid) is det | |
% source_sid_sel_ (-Type, -TNum, -Id, +Sid) is det | |
% source_new_sid_ (+Type, -Sid) is det | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
:- public | |
source_sid/2, | |
source_sid_key/2. | |
source_sid(source(Type, Id), Sid) :- | |
source_sid__do(Type, _, Id, Sid). | |
source_sid_type(Sid, Type) :- | |
source_sid__do(Type, _, _, Sid). | |
source_sid_key(Sid, Key) :- | |
var(Key), !, | |
source_sid__do(_, TNum, Id, Sid), | |
ACs = [nan_kernel__source__t, TNum, '__', Id], | |
atomic_list_concat(ACs, Key). | |
source_sid_key(Sid, Key) :- | |
atom_concat(nan_kernel__source__t, K1, Key), | |
sub_atom(K1, 0, 1, _, TVal), | |
sub_atom(K1, 3, _, 0, IdVal), | |
atom_number(TVal, TNum), | |
atom_number(IdVal, Id), | |
source_sid__num(type, TNum), | |
source_sid__num(id, Id), | |
source_sid_sel_(_, TNum, Id, Sid). | |
source_sid__do(Type, TNum, Id, Sid) :- | |
source_sid_sel_(Type, TNum, Id, Sid), | |
source_sid__num(type, TNum), | |
source_sid__num(id, Id). | |
source_sid_sel_(t1, 1, Id, t1(Id)) :- !. | |
source_sid_sel_(t0, 0, Id, t0(Id)). | |
source_sid__num(type, Num) :- | |
integer(Num), Num >= 0, Num =< 1. | |
source_sid__num(id, Num) :- | |
integer(Num), Num >= 0. | |
source_new_sid_(Type, Sid) :- | |
flag(nan_kernel__source, Id, Id + 1), | |
succ(Id, Id1), | |
source_sid_sel_(Type, _, Id1, Sid). | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See https://github.com/jp-diegidio/Nan.System.Sources-Prolog for an updated version (under GPLv3).