Skip to content

Commit 2d37839

Browse files
committed
Rule do not behave like RuleDelayed
1 parent 66de818 commit 2d37839

File tree

3 files changed

+36
-13
lines changed

3 files changed

+36
-13
lines changed

mathics/builtin/patterns.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ def create_rules(rules_expr, expr, name, evaluation, extra_args=[]):
172172
else:
173173
result = []
174174
for rule in rules:
175-
if rule.get_head_name() not in ("System`Rule", "System`RuleDelayed"):
175+
head_name = rule.get_head_name()
176+
if head_name not in ("System`Rule", "System`RuleDelayed"):
176177
evaluation.message(name, "reps", rule)
177178
return None, True
178179
elif len(rule.elements) != 2:
@@ -186,7 +187,13 @@ def create_rules(rules_expr, expr, name, evaluation, extra_args=[]):
186187
)
187188
return None, True
188189
else:
189-
result.append(Rule(rule.elements[0], rule.elements[1]))
190+
result.append(
191+
Rule(
192+
rule.elements[0],
193+
rule.elements[1],
194+
delayed=(head_name == "System`RuleDelayed"),
195+
)
196+
)
190197
return result, False
191198

192199

mathics/core/rules.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -131,18 +131,20 @@ class Rule(BaseRule):
131131
``G[1.^2, a^2]``
132132
"""
133133

134-
def __init__(self, pattern, replace, system=False) -> None:
134+
def __init__(self, pattern, replace, delayed=True, system=False) -> None:
135135
super(Rule, self).__init__(pattern, system=system)
136136
self.replace = replace
137+
self.delayed = delayed
137138

138139
def do_replace(self, expression, vars, options, evaluation):
139140
replace = self.replace
140-
while replace.has_form("System`Condition", 2):
141-
replace, cond = replace.elements
142-
cond = cond.replace_vars(vars)
143-
cond = cond.evaluate(evaluation)
144-
if cond is not SymbolTrue:
145-
return None
141+
if self.delayed:
142+
while replace.has_form("System`Condition", 2):
143+
replace, cond = replace.elements
144+
cond = cond.replace_vars(vars)
145+
cond = cond.evaluate(evaluation)
146+
if cond is not SymbolTrue:
147+
return None
146148

147149
new = replace.replace_vars(vars)
148150
new.options = options

test/builtin/test_patterns.py

+18-4
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,27 @@ def test_replace_all():
3030

3131
def test_rule_repl_cond():
3232
for str_expr, str_expected, message in (
33-
("f[x]/.(f[u_]->u^2/; u>3/; u>2)", "f[x]", "conditions are not evaluated"),
34-
("f[4]/.(f[u_]->u^2/; u>3/; u>2)", "16", "both conditions are True"),
33+
# For Rules, replacement is not evaluated
3534
(
36-
"f[2.5]/.(f[u_]->u^2/; u>3/; u>2)",
35+
"f[x]/.(f[u_]->u^2/; u>3/; u>2)",
36+
"x^2/; x>3/; x>2",
37+
"conditions are not evaluated in Rule",
38+
),
39+
(
40+
"f[4]/.(f[u_]->u^2/; u>3/; u>2)",
41+
"16 /; 4 > 3 /; 4 > 2",
42+
"still not evaluated, even if values are provided, due to the HoldAll attribute.",
43+
),
44+
# However, for delayed rules, the behavior is different:
45+
# Conditions defines if the rule is applied
46+
# and do not appears in the result.
47+
("f[x]/.(f[u_]:>u^2/; u>3/; u>2)", "f[x]", "conditions are not evaluated"),
48+
("f[4]/.(f[u_]:>u^2/; u>3/; u>2)", "16", "both conditions are True"),
49+
(
50+
"f[2.5]/.(f[u_]:>u^2/; u>3/; u>2)",
3751
"f[2.5]",
3852
"just the first condition is True",
3953
),
40-
("f[1.]/.(f[u_]->u^2/; u>3/; u>2)", "f[1.]", "Both conditions are False"),
54+
("f[1.]/.(f[u_]:>u^2/; u>3/; u>2)", "f[1.]", "Both conditions are False"),
4155
):
4256
check_evaluation(str_expr, str_expected, message)

0 commit comments

Comments
 (0)