/* Directive: multifile/2 allows multiple files to define facts for this predicate. This is useful for predicates like is_pre_statistic/2 that can be defined in different modules. */ :- multifile(is_pre_statistic/2). /* Directive: dynamic/2 declares the predicate as dynamic, meaning it can be modified during execution (assert/retract). */ :- dynamic(is_pre_statistic/2). /** * save_pre_statistic/1 * Save a pre-statistic state if it has not been saved before. * * @param Name Name of the statistic. */ save_pre_statistic(Name) :- /* Check if the statistic already exists, if so, do nothing. */ is_pre_statistic(Name, _) -> true ; ( /* If not, get the current statistics for the given name and store it as a pre-statistic. */ statistics(Name, AS), term_number(AS, FN), pfcAdd_Now(is_pre_statistic(Name, FN)) ). /** * pre_statistic/2 * Retrieve the previously saved statistic or return 0 if it does not exist. * * @param N Name of the statistic. * @param V Value of the statistic. */ pre_statistic(N, V) :- /* If the pre-statistic exists, return its value. Otherwise, return 0. */ is_pre_statistic(N, V) -> true ; V = 0. /** * post_statistic/2 * Compute the difference between the current statistic and the pre-statistic value. * * @param N Name of the statistic. * @param V The computed difference value. */ post_statistic(N, V) :- /* Get the current value of the statistic. */ statistics(N, VV), term_number(VV, FV), /* Retrieve the pre-statistic value, and calculate the difference. */ pre_statistic(N, WV), V0 is FV - WV, /* If the difference is negative, set the result to 0, otherwise use the difference. */ (V0 < 0 -> V = 0 ; V0 = V). /** * term_number/2 * Extract a number from a term. * * @param T The term. * @param N The extracted number. */ term_number(T, N) :- /* Use sub_term/2 to find any subterm that is a number within the term T. */ sub_term(N, T), number(N). /** * call_match/1 * Execute a list of goals sequentially or a single goal. * * @param G The goal(s) to be executed. * @example call_match([write('Hello'), nl]). */ call_match([G]) :- !, /* If there's only one goal in the list, call it. */ call(G). call_match([G|GG]) :- !, /* Call the first goal and then recursively call the remaining goals. */ call(G), call_match(GG). call_match(G) :- /* If a single goal (not a list), simply call it. */ call(G). /** * 'save-space!'/2 * Save atoms from a space to a file. * * @param Space The space from which to get atoms. * @param File The file to save the atoms to. */ 'save-space!'(Space, File) :- /* Use setup_call_cleanup/3 to ensure resources are properly cleaned up after use. */ setup_call_cleanup( /* Open the file for writing. */ open(File, write, Out, []), /* Write all atoms from the space to the file. */ with_output_to(Out, forall(get_atoms(Space, Atom), write_src(Atom))), /* Ensure the file is closed after writing. */ close(Out) ). /* Directive: dynamic/1 declares these predicates as dynamic. This allows us to modify them during the program execution. */ :- dynamic(repeats/1). :- dynamic(not_repeats/1). /** * assert_new/1 * Assert a fact if it does not already exist. * * @param P The fact to assert. */ assert_new(P) :- /* First, try to call the fact and succeed if it already exists. */ notrace(catch(call(P), _, fail)), !, /* If it exists, mark it as a repeated fact. */ assert_new1(repeats(P)). assert_new(P) :- /* Otherwise, add the fact and update the assert counter. */ pfcAdd_Now(P), flag(assert_new, TA, TA + 1), assert_new1(not_repeats(P)), !. /** * retract1/1 * Retract a fact only if it exists. * * @param P The fact to retract. */ retract1(P) :- /* If the fact does not exist, do nothing. */ \+ call(P), !. retract1(P) :- /* Otherwise, retract the fact. */ ignore(\+ retract(P)). /** * assert_new1/1 * Helper predicate to assert a fact if it is not already asserted. * * @param P The fact to assert. */ assert_new1(P) :- /* If the fact is already true, do nothing. */ \+ \+ call(P), !. assert_new1(P) :- /* Otherwise, assert the fact. */ pfcAdd_Now(P). /* Directive: dynamic/1 declares these predicates as dynamic. They can be asserted and retracted at runtime. */ :- dynamic(fb_pred/3). :- dynamic(mod_f_a/3). /** * decl_m_fb_pred/3 * Declare a module predicate, ensuring it's marked as dynamic. * * @param Mod The module. * @param Fn The predicate name. * @param A The arity of the predicate. */ decl_m_fb_pred(Mod, Fn, A) :- /* If Mod is a variable, retrieve it from mod_f_a/3. */ var(Mod), !, mod_f_a(Mod, Fn, A). decl_m_fb_pred(Mod, Fn, A) :- /* If the predicate already exists, do nothing. */ mod_f_a(Mod, Fn, A) -> true ; /* Otherwise, declare it as dynamic and assert it. */ (dynamic(Mod:Fn/A), pfcAdd_Now(mod_f_a(Mod, Fn, A))). /** * decl_fb_pred/2 * Declare a fact as a FlyBase predicate and track its originating file. * * @param Fn The predicate name. * @param A The arity of the predicate. */ :- dynamic(fb_pred_file/3). decl_fb_pred(Fn, A) :- /* If the predicate is already declared, do nothing. */ fb_pred(Fn, A) -> true ; ( /* Otherwise, declare it as dynamic and add it to the fb_pred database. */ dynamic(Fn/A), pfcAdd_Now(fb_pred(Fn, A)) ), /* Optionally track the file it was loaded from. */ ignore((nb_current(loading_file, File), (fb_pred_file(Fn, A, File) -> true ; pfcAdd_Now(fb_pred_file(Fn, A, File))) )). /* Directive: use_module/1 imports the readutil library, which provides predicates for reading input. */ :- use_module(library(readutil)). /** * skip/1 * Skip execution of a term. Used for commenting out code while keeping it for reference. * * @param _ Ignored argument. */ skip(_) :- true. % This predicate is used to skip over certain blocks of code. /* =============================== */ /* MeTTa Python incoming interface */ /* =============================== */ /* ============================ */ /* %%%% Atom Manipulations */ /* ============================ */ /** * 'clear-atoms'/1 * Clear all atoms from the specified space. * * @param SpaceNameOrInstance The space from which to clear atoms. */ 'clear-atoms'(SpaceNameOrInstance) :- /* Send a message to the output indicating which space is being cleared. */ dout(space, ['clear-atoms', SpaceNameOrInstance]), /* Find the method to clear the space based on its type, then call it. */ space_type_method(Type, clear_space, Method), call(Type, SpaceNameOrInstance), !, dout(space, ['type-method', Type, Method]), call(Method, SpaceNameOrInstance). /** * 'add-atom'/2 * Add an atom to the specified space. * * @param SpaceNameOrInstance The space to which the atom is added. * @param Atom The atom to add. */ 'add-atom'(SpaceNameOrInstance, Atom) :- /* Find the method to add an atom based on the space type, then call it. */ space_type_method(Type, add_atom, Method), call(Type, SpaceNameOrInstance), !, /* If the space is not a special type, log the action. */ if_t((SpaceNameOrInstance \== '&self' ; Type \== 'is_asserted_space'), dout(space, ['type-method', Type, Method, SpaceNameOrInstance, Atom])), call(Method, SpaceNameOrInstance, Atom). /** * 'add-atom'/3 * Add an atom to an environment and return the result. * * @param Environment The environment to add the atom to. * @param AtomDeclaration The atom declaration. * @param Result The result after adding the atom. */ 'add-atom'(Environment, AtomDeclaration, Result) :- /* Evaluate the 'add-atom' command with the given arguments. */ eval_args(['add-atom', Environment, AtomDeclaration], Result). /** * 'remove-atom'/2 * Remove an atom from the specified space. * * @param SpaceNameOrInstance The space from which the atom is removed. * @param Atom The atom to remove. */ 'remove-atom'(SpaceNameOrInstance, Atom) :- /* Send a message to the output indicating the atom is being removed. */ dout(space, ['remove-atom', SpaceNameOrInstance, Atom]), /* Find the method to remove an atom based on the space type, then call it. */ space_type_method(Type, remove_atom, Method), call(Type, SpaceNameOrInstance), !,