From 52d93f7320dd2feacfc601d8d20e16baa4d55a9c Mon Sep 17 00:00:00 2001 From: Mike Archbold Date: Tue, 27 Aug 2024 17:30:50 -0700 Subject: [PATCH 1/6] sealing work in progress --- src/canary/metta_eval.pl | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/canary/metta_eval.pl b/src/canary/metta_eval.pl index 218a378ec24..1a28a11922f 100755 --- a/src/canary/metta_eval.pl +++ b/src/canary/metta_eval.pl @@ -628,6 +628,63 @@ set_last_error(_). + +% ================================================================= +% ================================================================= +% ================================================================= +% SCOPING +% ================================================================= +% ================================================================= +% ================================================================= + +eval_20(Eq, RetType, Depth, Self, ['sealed', InputVarList, Expr], Result) :- + is_list(InputVarList), + % second argument is a list of variables to be sealed. Create a temporary variable to use for each. + maplist(create_unique_var, InputVarList, UniqueVarMap), + % create lookup table [sealed --> local] + LocalVarLookup = [InputVarList, UniqueVarMap], + write("lookup>"),writeln(LocalVarLookup), + write("input expr>"),writeln(Expr), + replace_vars_in_expr(Expr, LocalVarLookup, Result), + write("new expr>"),writeln(Result). + +% create temp local variables for each variable in VarList +create_unique_var(InVar, OutVarUnique) :- + random(0, 1000000, Num), + atom_concat('_', Num, NumbVar), + atom_concat('$Local',NumbVar,OutVarUnique). + +% --> Swap in the local variables if found in the input MeTTa Expr + +% lookup if we need to use a local variable +check_replace_with_local_var(VarCheckIn, [VarKeys|[VarValues]], VarCheckOut) :- + nth1(Index, VarKeys, VarCheckIn),write(" KeyIn>"),write(VarCheckIn), + nth1(Index, VarValues, VarCheckOut),write(" ValOut>"),write(VarCheckOut) + . + +% --> replace_vars_in_expr( input expression list, local variable map, output expression with temp local) + +% Base case: empty list +replace_vars_in_expr([], _, []). + +% Base case: return Atom if Atom +replace_vars_in_expr(Atom,_,Atom) :- + atomic(Atom). + +% If variable, check if we need to swap in sealed local variable +replace_vars_in_expr([H|T], LocalVarLookup, Result) :- + var(H), % trap on unbound variable + check_replace_with_local_var(H, LocalVarLookup, VarCheckedOut), + replace_vars_in_expr(T, LocalVarLookup, ResultRest), + Result = [VarCheckedOut|ResultRest]. + +% All other cases... +replace_vars_in_expr([H|T], LocalVarLookup, Result) :- + replace_vars_in_expr(H, LocalVarLookup, ResultHead), + replace_vars_in_expr(T, LocalVarLookup, ResultTail), + Result = [ ResultHead | ResultTail ]. + + % ================================================================= % ================================================================= % ================================================================= From b6ff1d2e761e00c7058d9910dc3a7830f278582b Mon Sep 17 00:00:00 2001 From: Mike Archbold Date: Tue, 27 Aug 2024 17:33:50 -0700 Subject: [PATCH 2/6] sealing work in progress --- src/canary/metta_eval.pl | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/canary/metta_eval.pl b/src/canary/metta_eval.pl index 1a28a11922f..956889f1ec7 100755 --- a/src/canary/metta_eval.pl +++ b/src/canary/metta_eval.pl @@ -643,10 +643,7 @@ maplist(create_unique_var, InputVarList, UniqueVarMap), % create lookup table [sealed --> local] LocalVarLookup = [InputVarList, UniqueVarMap], - write("lookup>"),writeln(LocalVarLookup), - write("input expr>"),writeln(Expr), - replace_vars_in_expr(Expr, LocalVarLookup, Result), - write("new expr>"),writeln(Result). + replace_vars_in_expr(Expr, LocalVarLookup, Result). % create temp local variables for each variable in VarList create_unique_var(InVar, OutVarUnique) :- @@ -658,9 +655,8 @@ % lookup if we need to use a local variable check_replace_with_local_var(VarCheckIn, [VarKeys|[VarValues]], VarCheckOut) :- - nth1(Index, VarKeys, VarCheckIn),write(" KeyIn>"),write(VarCheckIn), - nth1(Index, VarValues, VarCheckOut),write(" ValOut>"),write(VarCheckOut) - . + nth1(Index, VarKeys, VarCheckIn), + nth1(Index, VarValues, VarCheckOut). % --> replace_vars_in_expr( input expression list, local variable map, output expression with temp local) From fb82a24a01934ce878056eb9d78cdd1dcc1412b3 Mon Sep 17 00:00:00 2001 From: Mike Archbold Date: Thu, 29 Aug 2024 15:00:45 -0700 Subject: [PATCH 3/6] sealing work in progress, revision for recommended changes --- src/canary/metta_eval.pl | 91 +++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/src/canary/metta_eval.pl b/src/canary/metta_eval.pl index b215b53939e..ae45766a05e 100755 --- a/src/canary/metta_eval.pl +++ b/src/canary/metta_eval.pl @@ -662,48 +662,55 @@ % ================================================================= eval_20(Eq, RetType, Depth, Self, ['sealed', InputVarList, Expr], Result) :- - is_list(InputVarList), - % second argument is a list of variables to be sealed. Create a temporary variable to use for each. - maplist(create_unique_var, InputVarList, UniqueVarMap), - % create lookup table [sealed --> local] - LocalVarLookup = [InputVarList, UniqueVarMap], - replace_vars_in_expr(Expr, LocalVarLookup, Result). - -% create temp local variables for each variable in VarList -create_unique_var(InVar, OutVarUnique) :- - random(0, 1000000, Num), - atom_concat('_', Num, NumbVar), - atom_concat('$Local',NumbVar,OutVarUnique). - -% --> Swap in the local variables if found in the input MeTTa Expr - -% lookup if we need to use a local variable -check_replace_with_local_var(VarCheckIn, [VarKeys|[VarValues]], VarCheckOut) :- - nth1(Index, VarKeys, VarCheckIn), - nth1(Index, VarValues, VarCheckOut). - -% --> replace_vars_in_expr( input expression list, local variable map, output expression with temp local) - -% Base case: empty list -replace_vars_in_expr([], _, []). - -% Base case: return Atom if Atom -replace_vars_in_expr(Atom,_,Atom) :- - atomic(Atom). - -% If variable, check if we need to swap in sealed local variable -replace_vars_in_expr([H|T], LocalVarLookup, Result) :- - var(H), % trap on unbound variable - check_replace_with_local_var(H, LocalVarLookup, VarCheckedOut), - replace_vars_in_expr(T, LocalVarLookup, ResultRest), - Result = [VarCheckedOut|ResultRest]. - -% All other cases... -replace_vars_in_expr([H|T], LocalVarLookup, Result) :- - replace_vars_in_expr(H, LocalVarLookup, ResultHead), - replace_vars_in_expr(T, LocalVarLookup, ResultTail), - Result = [ ResultHead | ResultTail ]. - + % sanitize input variables and expression (omit numbers) + term_variables(InputVarList, SanitizedSealedVars), + term_variables(Expr, SanitizedExprVars), + strict_intersection(SanitizedSealedVars,SanitizedExprVars,SealedVars), + check_replace_with_local_var(SealedVars, Expr, Result). + +% Strict member check needed for variables: +strict_member(X, [H|_]) :- + X == H. +strict_member(X, [_|T]) :- + strict_member(X, T). + +% Strict intersection of two lists +strict_intersection([], _, []). +strict_intersection([H|T], List2, [H|Result]) :- + strict_member(H, List2), + !, + strict_intersection(T, List2, Result). +strict_intersection([_|T], List2, Result) :- + strict_intersection(T, List2, Result). + +% Boundary case -- no remaining variables to process, just return expression. +check_replace_with_local_var([], Expr, Result) :- + Result = Expr. + +% General case -- replace sealed variable with a new variable +check_replace_with_local_var([VarHead|VarTail], Expr, Result) :- + % '_' gives us a prolog variable + subst(Expr, VarHead, _, NewExpr), + check_replace_with_local_var(VarTail, NewExpr, Result). + +%! subst(+Term, +OldTerm, +NewTerm, -ResultTerm) is det. +% +% Recursively substitutes occurrences of OldTerm with NewTerm within a Prolog term (Term), +% producing a new term (ResultTerm). This predicate handles both simple and compound terms, including lists. + +% If the current term (Term) exactly matches OldTerm (Like identical variables), it is replaced by NewTerm. +subst(Term, OldTerm, NewTerm, NewTerm) :- OldTerm == Term, !. +% If the current term is not a compound term (like an atom, number or the wrong variable) it stays the same +subst(Term, _, _, Term) :- \+ compound(Term), !. +% If the current term is a list, it processes each element of the list recursively. +subst([Old|Structure], OldTerm, NewTerm, [New|StructureO]) :- !, + subst(Old, OldTerm, NewTerm, New), + subst(Structure, OldTerm, NewTerm, StructureO). +% Compound Terms are decomposed and reconstructed with the possibly modified arguments. +subst(OldStructure, OldTerm, NewTerm, NewStructure) :- + OldStructure =.. [Functor|Args], + subst(Args, OldTerm, NewTerm, NewArgs), + NewStructure =.. [Functor|NewArgs]. % ================================================================= % ================================================================= From c5a65a8e45ea00205685f23839d3765abfedbbdb Mon Sep 17 00:00:00 2001 From: Mike Archbold Date: Fri, 30 Aug 2024 11:06:14 -0700 Subject: [PATCH 4/6] sealed updates for same_term --- src/canary/metta_eval.pl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/canary/metta_eval.pl b/src/canary/metta_eval.pl index d140b5ef41c..ce6710ac428 100755 --- a/src/canary/metta_eval.pl +++ b/src/canary/metta_eval.pl @@ -671,20 +671,18 @@ % ================================================================= % ================================================================= -eval_20(Eq, RetType, Depth, Self, ['sealed', InputVarList, Expr], Result) :- - % sanitize input variables and expression (omit numbers) - term_variables(InputVarList, SanitizedSealedVars), - term_variables(Expr, SanitizedExprVars), - strict_intersection(SanitizedSealedVars,SanitizedExprVars,SealedVars), +eval_20(Eq, RetType, Depth, Self, ['sealed', InputVarList, Expr], Result) :- !, + strict_intersection(InputVarList,Expr,SealedVars), check_replace_with_local_var(SealedVars, Expr, Result). -% Strict member check needed for variables: +% strict_member(+Term, +List) strict_member(X, [H|_]) :- - X == H. + same_term(X,H). strict_member(X, [_|T]) :- strict_member(X, T). % Strict intersection of two lists +% strict_intersection(+List1, +List2, -Intersection). strict_intersection([], _, []). strict_intersection([H|T], List2, [H|Result]) :- strict_member(H, List2), @@ -693,6 +691,7 @@ strict_intersection([_|T], List2, Result) :- strict_intersection(T, List2, Result). +% check_replace_with_local_var(+Sealed-Variables, +Expression, -NewExpression) % Boundary case -- no remaining variables to process, just return expression. check_replace_with_local_var([], Expr, Result) :- Result = Expr. @@ -708,8 +707,8 @@ % Recursively substitutes occurrences of OldTerm with NewTerm within a Prolog term (Term), % producing a new term (ResultTerm). This predicate handles both simple and compound terms, including lists. -% If the current term (Term) exactly matches OldTerm (Like identical variables), it is replaced by NewTerm. -subst(Term, OldTerm, NewTerm, NewTerm) :- OldTerm == Term, !. +% If the current term (Term) exactly matches OldTerm it is replaced by NewTerm. +subst(Term, OldTerm, NewTerm, NewTerm) :- same_term(OldTerm, Term), !. % If the current term is not a compound term (like an atom, number or the wrong variable) it stays the same subst(Term, _, _, Term) :- \+ compound(Term), !. % If the current term is a list, it processes each element of the list recursively. From 086e35e18b421964c74d5b103cc81f5ff2d95e3f Mon Sep 17 00:00:00 2001 From: Mike Archbold Date: Fri, 30 Aug 2024 19:21:26 -0700 Subject: [PATCH 5/6] sealing work in progress continued --- src/canary/metta_eval.pl | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/canary/metta_eval.pl b/src/canary/metta_eval.pl index ce6710ac428..4e5ae12877a 100755 --- a/src/canary/metta_eval.pl +++ b/src/canary/metta_eval.pl @@ -672,31 +672,24 @@ % ================================================================= eval_20(Eq, RetType, Depth, Self, ['sealed', InputVarList, Expr], Result) :- !, - strict_intersection(InputVarList,Expr,SealedVars), - check_replace_with_local_var(SealedVars, Expr, Result). - -% strict_member(+Term, +List) -strict_member(X, [H|_]) :- - same_term(X,H). -strict_member(X, [_|T]) :- - strict_member(X, T). - -% Strict intersection of two lists -% strict_intersection(+List1, +List2, -Intersection). -strict_intersection([], _, []). -strict_intersection([H|T], List2, [H|Result]) :- - strict_member(H, List2), + omit_atoms(InputVarList,OutputVarList), + check_replace_with_local_var(OutputVarList, Expr, Result). + +% omit_atoms(+input variables, -variables less atoms) +omit_atoms([], []). +omit_atoms([Head|Tail], Result) :- + atomic(Head), !, - strict_intersection(T, List2, Result). -strict_intersection([_|T], List2, Result) :- - strict_intersection(T, List2, Result). + omit_atoms(Tail, Result). +omit_atoms([Head|Tail], [Head|Result]) :- + omit_atoms(Tail, Result). % check_replace_with_local_var(+Sealed-Variables, +Expression, -NewExpression) % Boundary case -- no remaining variables to process, just return expression. check_replace_with_local_var([], Expr, Result) :- Result = Expr. -% General case -- replace sealed variable with a new variable +% General case -- replace sealed variable with a new variable check_replace_with_local_var([VarHead|VarTail], Expr, Result) :- % '_' gives us a prolog variable subst(Expr, VarHead, _, NewExpr), @@ -707,14 +700,21 @@ % Recursively substitutes occurrences of OldTerm with NewTerm within a Prolog term (Term), % producing a new term (ResultTerm). This predicate handles both simple and compound terms, including lists. -% If the current term (Term) exactly matches OldTerm it is replaced by NewTerm. -subst(Term, OldTerm, NewTerm, NewTerm) :- same_term(OldTerm, Term), !. +% Note: Matching is done with the SWI same_term predicate which states that terms are equal if the +% condition "the same variable, equivalent atomic data or a compound term allocated at the same address" +% If the current term (Term) exactly matches OldTerm (with above criteria). +subst(Term, OldTerm, NewTerm, NewTerm) :- + same_term(OldTerm, Term), + !. + % If the current term is not a compound term (like an atom, number or the wrong variable) it stays the same subst(Term, _, _, Term) :- \+ compound(Term), !. + % If the current term is a list, it processes each element of the list recursively. subst([Old|Structure], OldTerm, NewTerm, [New|StructureO]) :- !, subst(Old, OldTerm, NewTerm, New), subst(Structure, OldTerm, NewTerm, StructureO). + % Compound Terms are decomposed and reconstructed with the possibly modified arguments. subst(OldStructure, OldTerm, NewTerm, NewStructure) :- OldStructure =.. [Functor|Args], From 5e5092f4365d43521afadec7cbdf493786dc9591 Mon Sep 17 00:00:00 2001 From: Mike Archbold Date: Fri, 30 Aug 2024 21:05:56 -0700 Subject: [PATCH 6/6] sealing work in progress continued --- src/canary/metta_eval.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/canary/metta_eval.pl b/src/canary/metta_eval.pl index 4e5ae12877a..f774029071e 100755 --- a/src/canary/metta_eval.pl +++ b/src/canary/metta_eval.pl @@ -676,6 +676,7 @@ check_replace_with_local_var(OutputVarList, Expr, Result). % omit_atoms(+input variables, -variables less atoms) +% If there are already bound values passed to sealed, no need for replacement omit_atoms([], []). omit_atoms([Head|Tail], Result) :- atomic(Head),