Create contains, eq and replace operations
parent
dcad494c7d
commit
66beff5792
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Callable
|
||||
from typing import Callable, Generator
|
||||
|
||||
import copy
|
||||
|
||||
|
|
@ -24,6 +24,24 @@ USABLE_VAR_NAMES = [
|
|||
'μ', 'ν', 'ξ', 'ο', 'π', 'ρ', 'σ', 'τ', 'υ', 'φ', 'χ', 'ψ', 'ω'
|
||||
]
|
||||
|
||||
def contains(haystack : Term, needle : Term) -> bool:
|
||||
"""
|
||||
Determine whether a given small term value is contained in a bigger
|
||||
term.
|
||||
|
||||
:param haystack: The term to search through.
|
||||
:type haystack: Term
|
||||
:param needle: The term to find.
|
||||
:type needle: Term
|
||||
:return: Whether the needle was found in the haystack.
|
||||
:rtype: bool
|
||||
"""
|
||||
for term in haystack.rec_iter():
|
||||
if term == needle:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def normalize(term : Term) -> Term:
|
||||
"""
|
||||
Create a normalization function. This function simplifies functions as
|
||||
|
|
@ -78,6 +96,21 @@ def std_norm_iter(term : Term) -> Term:
|
|||
return term
|
||||
_known_norms.append(std_norm_iter)
|
||||
|
||||
def replace(term : Term, old : Term, new : Term) -> Term:
|
||||
"""
|
||||
Find and replace occurrences of a sub-term in a given term.
|
||||
|
||||
:param term: The original term to update.
|
||||
:type term: Term
|
||||
:param old: The term to find and replace.
|
||||
:type old: Term
|
||||
:param new: The new term to replace the old one with.
|
||||
:type new: Term
|
||||
:return: The replaced term result.
|
||||
:rtype: Term
|
||||
"""
|
||||
return traverse_bottom_up(f=lambda t : new if t == old else t, term=term)
|
||||
|
||||
def traverse(f : Callable[[Term], Term], term : Term) -> Term:
|
||||
"""
|
||||
Traverse through the tree back-and-forth, aiming to run the given
|
||||
|
|
@ -96,7 +129,7 @@ def traverse(f : Callable[[Term], Term], term : Term) -> Term:
|
|||
a, b = Term(), term
|
||||
|
||||
while a != b:
|
||||
a, b = b, traverse_bottom_up(f=f, term=traverse_top_down(f=f, term=term))
|
||||
a, b = b, traverse_bottom_up(f=f, term=traverse_top_down(f=f, term=b))
|
||||
|
||||
return b
|
||||
|
||||
|
|
@ -171,12 +204,6 @@ class Term:
|
|||
Base class for all terms.
|
||||
"""
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
"""
|
||||
Determine whether two terms are equal.
|
||||
"""
|
||||
return str(self) == str(other)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Create a representation of a term.
|
||||
|
|
@ -186,6 +213,12 @@ class Term:
|
|||
def normalize(self) -> Term:
|
||||
return normalize(term=self)
|
||||
|
||||
def replace(self, old : Term, new : Term) -> Term:
|
||||
return replace(term=self, old=old, new=new)
|
||||
|
||||
def rec_iter(self) -> Generator[Term, None, None]:
|
||||
yield self
|
||||
|
||||
def to_str(self, vars : dict[str, Var]) -> str:
|
||||
return "<undefined>"
|
||||
|
||||
|
|
@ -205,6 +238,11 @@ class App(Term):
|
|||
"""
|
||||
return self.to_str(vars={})
|
||||
|
||||
def rec_iter(self) -> Generator[Term, None, None]:
|
||||
yield self
|
||||
yield from self.f.rec_iter()
|
||||
yield from self.x.rec_iter()
|
||||
|
||||
def to_str(self, vars: dict[str, Var]) -> str:
|
||||
f_str = self.f.to_str(vars=vars)
|
||||
x_str = self.x.to_str(vars=vars)
|
||||
|
|
@ -246,6 +284,18 @@ class Lambda(Term):
|
|||
out : Term
|
||||
var : Var
|
||||
|
||||
def __eq__(self, value: object) -> bool:
|
||||
if not isinstance(value, Lambda):
|
||||
return False
|
||||
|
||||
for c in USABLE_VAR_NAMES:
|
||||
if not contains(self.out, Const(c)):
|
||||
return self.substitute(Const(c)) == value.substitute((Const(c)))
|
||||
else:
|
||||
raise ValueError(
|
||||
"Ran out of usable variables for comparing lambda structures"
|
||||
)
|
||||
|
||||
def __init__(self, f : Callable[[Var], Term]) -> None:
|
||||
self.var = Var()
|
||||
self.out = f(self.var)
|
||||
|
|
@ -256,6 +306,10 @@ class Lambda(Term):
|
|||
"""
|
||||
return self.to_str(vars={})
|
||||
|
||||
def rec_iter(self) -> Generator[Term, None, None]:
|
||||
yield self
|
||||
yield from self.out.rec_iter()
|
||||
|
||||
def replace_content(self, term : Term) -> Lambda:
|
||||
"""
|
||||
Replace the content of the lambda function with the given term.
|
||||
|
|
@ -427,3 +481,15 @@ if __name__ == "__main__":
|
|||
g = L1(lambda b : A2(b, bool_f, bool_t))
|
||||
print(g)
|
||||
print(g.normalize())
|
||||
|
||||
print("\nFIND & REPLACE")
|
||||
print(30 * "=")
|
||||
|
||||
h = A3(Const("f"), Const("x"), Const("y"), Const("z"))
|
||||
i = A3(Const("f"), Const("x"), Const("b"), Const("z")).replace(
|
||||
old=Const("b"), new=Const("y"),
|
||||
)
|
||||
|
||||
print(h)
|
||||
print(i)
|
||||
assert h == i
|
||||
|
|
|
|||
Loading…
Reference in New Issue