I have read your paper, @pmoura , the other day when I was thinking it might be possible to (from the Web Prolog user’s point of view) get rid of modules and the complications with meta_predicate/1
altogether. (It doesn’t seem likely though, as long as the workspace of an actor is provided by a module.)
Today, I’m getting more and more frustrated by my so far failed attempts to get my receive/1-2
to work correctly when in a module. Unfortunately, reading your paper didn’t help. As a reminder, here’s the predicate I’m talking about:
receive(Clauses, Options) :-
thread_self(Mailbox),
( clause(deferred(Message), true, Ref),
select_rclause_body(Clauses, Message, Body)
-> erase(Ref),
call(Body)
; receive(Mailbox, Clauses, Options)
).
receive(Mailbox, Clauses, Options) :-
( thread_get_message(Mailbox, Message, Options)
-> ( select_rclause_body(Clauses, Message, Body)
-> call(Body)
; assertz(deferred(Message)),
receive(Mailbox, Clauses, Options)
)
; option(on_timeout(Body), Options, true),
call(Body)
).
select_rclause_body({PatternGuard -> Body}, Message, Body) :-
var(PatternGuard), !,
PatternGuard = Message.
select_rclause_body({PatternGuard -> Body}, Message, Body) :-
check(PatternGuard, Message).
select_rclause_body({PatternGuard -> Body ; _}, Message, Body) :-
check(PatternGuard, Message), !.
select_rclause_body({_ ; Rules}, Message, Body) :-
select_rclause_body({Rules}, Message, Body).
check(Pattern when Guard, Message) :- !,
Message = Pattern,
once(Guard).
check(Pattern, Pattern).
I use this with two test programs:
:- op(1000, xfy, when).
important(Messages) :-
receive({
Priority-Message when Priority > 10 ->
Messages = [Message|MoreMessages],
important(MoreMessages)
},[ timeout(0),
on_timeout(normal(Messages))
]).
normal(Messages) :-
receive({
_-Message ->
Messages = [Message|MoreMessages],
normal(MoreMessages)
},[ timeout(0),
on_timeout(Messages=[])
]).
and
wait_hello :-
receive({
hello ->
writeln('Got hello!'),
wait_goodbye
}).
wait_goodbye :-
receive({
goodbye ->
writeln('Got goodbye!')
}).
I’ve managed to make the important/1
program to work (ab)using the following meta predicate declaration and code:
:- meta_predicate receive(:,:).
receive(Clauses) :-
receive(Clauses, []).
receive(M:Clauses, M:Options) :-
thread_self(Mailbox),
( clause(deferred(Message), true, Ref),
select_rclause_body(Clauses, Message, Body)
-> erase(Ref),
call(M:Body)
; receive(Mailbox, M:Clauses, M:Options)
).
receive(Mailbox, M:Clauses, M:Options) :-
( thread_get_message(Mailbox, Message, Options)
-> ( select_rclause_body(Clauses, Message, Body)
-> call(M:Body)
; assertz(deferred(Message)),
receive(Mailbox, M:Clauses, M:Options)
)
; option(on_timeout(Body), Options, true),
call(M:Body)
).
select_rclause_body({PatternGuard -> Body}, Message, Body) :-
var(PatternGuard), !,
PatternGuard = Message.
select_rclause_body({PatternGuard -> Body}, Message, Body) :-
check(PatternGuard, Message).
select_rclause_body({PatternGuard -> Body ; _}, Message, Body) :-
check(PatternGuard, Message), !.
select_rclause_body({_ ; Rules}, Message, Body) :-
select_rclause_body({Rules}, Message, Body).
check(Pattern when Guard, Message) :- !,
Message = Pattern,
once(Guard).
check(Pattern, Pattern).
(I know, it wont work if the second argument to when
isn’t a built-in.)
The wait_hello/1
program doesn’t work though, although it’s actually simpler. When I run it, I get this error:
Got hello!
ERROR: Unknown procedure: receive:wait_goodbye/0
ERROR: However, there are definitions for:
ERROR: test:wait_goodbye/0
...
Since I’m calling Body
in the module M
everywhere, I don’t understand how this can happen!
Help with this would be much appreciated!