I’m using: SWI-Prolog version 8.0.2 on Ubuntu Linux 18.04.
If I want to expose predicates in the code I pass to PEngines during a PEngines create() call, via the src_text module, can I simply add a module declaration at the top of the code in the src-text parameter? If so, should I use the exact name user to declare the module, since it appears that PEngines assigns that name to the code loaded via src_text?
For example, putting something like this at the top of the code in src_text:
So that could that is pre-loaded on to the server could call back into the code loaded via src_text like this: user:callable_by_non_user_code(X)?
If not, what is the correct procedure for declaring predicates that will be called by code that was loaded into the PEngines server at startup? Also, any problems or warnings I should know about when doing this?
The src_text value is loaded into the Pengines temporary module. This cannot be a global module. Simply consider that Pengines are designed to be safe. Using a global module with a user name would lead to conflicts and global modules may have dependencies anywhere and thus cannot be destroyed safely.
The only way to create a module playing a role is to write this module as a normal module file on the server and load it during application startup. Here, the server manager is responsible for the safety. Now you have two options. You can use
to make its predicates available as default predicates to all pengine instances. Or you use
:- use_module(myfile, ).
to load the module but do not expose its interface. Now a Pengine can use use_module/1,2 to make the module available to the pengine. The module must be preloaded into the server such that the use_module in the pengine doesn’t trigger actual loading. Loading files is allowed from Pengines, but with severe sandbox limitations that allow it to load only really clean code with completely safe declarations.
But that’s the problem. I can’t call the predicates in the code I load via the src_text property via an ask() call as I stated in this thread:
That’s what prompted me to try turning the code I load in the src_text property into a module. I know the pengine_execute_single_user_action() predicate is definitely there as you can see in the `src_text property here:
Error: procedure `'7cd30558-35dc-4ba6-9d64-348ba0837c11':pengine_execute_single_user_action(A,B)' does not exist
"data": "procedure `'7cd30558-35dc-4ba6-9d64-348ba0837c11':pengine_execute_single_user_action(A,B)' does not exist",
"src_text": "% ===================== EXECUTE A USER COMMAND =======================\n% ----->>>>> execute_user_action_list\n%\n%\tThis predicate executes a list of actions and then accumulates the\n%\t\tevents generated in the per-volley temporary database predicate\n%\t\tin order to build a full response to the caller.\n\n% All actions executed\nexecute_user_action_list_1() :- !.\n\n% Execute the next action.\nexecute_user_action_list_1([Action | Action_T]) :-\n\tnonvar(Action),\n\t% Execute the next action.\n\tcall(Action),\n\t!,\n\texecute_user_action_list_1(Action_T).\n\n% This predicate is here to skip failed actions so that\n% other actions can be tried.\n% TODO: Revisit the soundness of the above strategy.\nexecute_user_action_list_1([_ | Action_T]) :-\n\t!,\n\t% Skip the action.\n\texecute_user_action_list_1(Action_T).\n\nexecute_user_action_list(ActionList, Response) :-\n\tnonvar(ActionList),\n\t% Clear out the database predicate clauses that accumulate\n\t%\tas events are added to the database during the current\n\t%\tvolley.\n\tu_retractall(temp(_)),\n\t% Execute the given list of actions. The events generated\n\t%\twill accumulate in the temp predicate.\n\texecute_user_action_list_1(ActionList),\n\t% Build our response for this volley.\n\tcreate_response(Response),\n\t!.\n\n% ----->>>>> execute_single_user_action\n%\tHelper function to execute just one user action.\nexecute_single_user_action(Action, Response) :-\n\tnonvar(Action),\n\texecute_user_action_list([Action], Response).\n\n% ----->>>>> pengine_execute_single_user_action\n\n%\tHelper function to execute just one user action.\n**pengine_execute_single_user_action**(Action, Response) :-\n\tnonvar(Action),\n\texecute_user_action_list([Action], Response),\n\t!.\n\t% item_to_dict(Response, JsonTerm).\n",
But as I show in that other thread, I get an existence error when I try to call it from an ask() call, with or without having a module declaration at the top of the src_text code.
% ----->>>>> execute_single_user_action
% Helper function to execute just one user action.
execute_single_user_action(Action, Response) :-
% ----->>>>> pengine_execute_single_user_action
% Helper function to execute just one user action.
**pengine_execute_single_user_action**(Action, Response) :-
% item_to_dict(Response, JsonTerm).
That is including the double ** around the predicate. Now I do not know where these come from (possibly from copy/paste in thus forum), but if they are really in your code you should have got an onoutput event that captures errors and warnings during compilation.
Of course not. I only put that there in the exact format so you could see that I had not made the simple mistake of not actually having a predicate of that name in the src_text property.
That is why I tried highlighting the predicate name in bold so you did not have to visually parse that long string to see that the predicate’s name is indeed in it. Unfortunately the forum software does not support additional styles inside of a code block so it shows the raw bold characters around the predicate name, that of a pair of double asterisks, instead of making it bold. So it was not a copy and paste error nor the error of actually having those characters in the actual source code. It was my (failed) attempt to highlight the predicate name in the src_text parameter.
To recapitulate, I can’t call predicates that are definitely found in the src_text parameter from a PEngines ask() call. I do not get any errors during during the PEngines create() call so I assume the code is sound. If you have any tips on how I might fix or debug this problem I would appreciate it.
You could also run ?- tspy(http_pengine_create). and see what happens.
In other words, if you don’t make this change then adding a src_text option to your pengine_create statement does nothing. I’m able to make proper calls now. I’m having a strange problem where variables in my query are not getting bound to anything yet, but at least I’m up and running. Thank you for your help.