| name | use-table-driven-rules |
| description | For rule-based systems: store rules as data, easier to add/modify than if-elif chains, simplification tables, configuration. |
use-table-driven-rules
When to Use
- Many special cases (simplification rules)
- Configuration-driven behavior
- Lookup tables
- State machines
- Rules that change frequently
- Making rules visible/maintainable
When NOT to Use
- Few simple cases (use if-elif)
- Rules require complex logic
- Order of evaluation matters in complex ways
The Pattern
Store rules in data structures instead of code.
def simplify(expr):
if expr == ('+', 0, x): return x
if expr == ('+', x, 0): return x
if expr == ('*', 1, x): return x
...
simp_rules = {
('+', 0, 'x'): 'x',
('+', 'x', 0): 'x',
('*', 1, 'x'): 'x',
('*', 'x', 1): 'x',
('*', 0, 'x'): 0,
}
def simplify(expr):
pattern = generalize(expr)
if pattern in simp_rules:
return instantiate(simp_rules[pattern], expr)
return expr
Example (from pytudes)
simp_table = {
sin(0): 0,
sin(pi): 0,
sin(pi/2): 1,
cos(0): 1,
cos(pi): -1,
cos(pi/2): 0,
tan(0): 0,
ln(1): 0,
ln(e): 1,
}
def simp(y):
"""Simplify expression using table and rules."""
if y in simp_table:
return simp_table[y]
arrow_direction = {
'^': (0, -1),
'v': (0, 1),
'>': (1, 0),
'<': (-1, 0),
'.': (0, 0),
}
def move(pos, arrow):
dx, dy = arrow_direction[arrow]
return (pos[0] + dx, pos[1] + dy)
factor = {: +, : -}
():
.diff += factor[direction] * (word)
env = {
: op.add,
: op.sub,
: op.mul,
: op.truediv,
}
Key Principles
- Data over code: Rules as dict entries, not if statements
- Easy to extend: Adding rule = adding dict entry
- Visible rules: Can print/inspect the table
- Consistent lookup: All rules checked same way
- Fallback logic: Handle missing keys gracefully