规则引擎的设计和实现(一)
先占坑,有时间再加注释和改进,然后写一下如何应用。
规则引擎是什么
…
一个简单的实现
我们的配置文件长啥样呢
(and (or_ (and 1 2) (gt_ 2 1) (contain_ 规则引擎的设计和实现 规则))
类似上面的 lisp 语言的写法定义,函数的支持,需要自己定义。
class RuleEngine(object):
def __init__(self, rules, slot):
self.rules = open(rules, 'r').read() # Json.load(CONF_RULES)
def parse(self, program):
return self.read_from_token(self.tokenize(program))
def tokenize(self, s):
return s.replace('(', ' ( ').replace(')', ' ) ').split()
def read_from_token(self, tokens):
if len(tokens) == 0:
raise SyntaxError('unexpected EOF while reading')
token = tokens.pop(0)
if '(' == token:
L = []
while tokens[0] != ')':
L.append(self.read_from_token(tokens))
tokens.pop(0)
return L
elif ')' == token:
raise SyntaxError('unexpected )')
else:
return self.atom(token)
def atom(self, token):
try:
return int(token)
except ValueError:
try:
return float(token)
except ValueError:
return str(token)
# 这里的实现比较的 low,其实用该放到一个 global env 中
# 这样我们就可以在配置中实现变量的定义,函数的定义了
# 本质上其实是一个 lisp 的解释器
class Functions(object):
def eq_(self, *args):
if len(args) > 1:
return args[0] == args[1]
return False
def gt_(self, *args):
if len(args) > 1:
return args[0] > args[1]
return False
def ge_(self, *args):
if len(args) > 1:
return args[0] >= args[1]
return False
def lt_(self, *args):
if len(args) > 1:
return args[0] < args[1]
def le_(self, *args):
if len(args) > 1:
return args[0] <= args[1]
return False
def or_(self, *args):
return any(args)
def ne_(self, *args):
return args[0] != args[1]
def and_(self, *args):
return all(args)
def int_(self, *args):
return int(args[0])
def float_(self, *args):
return float(args[0])
def str_(self, *args):
return str(args[0])
def contain_(self, *args):
if len(args) > 1:
return re.search(r'{}'.format(args[1]), args[0])
return False
# 注意理解这里的递归处理,这是关键的一步
def _eval(self, rules, fns):
def _recurse_eval(args):
if isinstance(args, list):
return self._eval(args, fns)
else:
return args
r = list(map(_recurse_eval, rules))
func = getattr(fns, r[0])
return func(*r[1:])
def eval(self):
r = self.parse(self.rules)
fns = self.Functions()
ret = self._eval(r, fns)
if not isinstance(ret, bool):
raise Exception("Error..")
return ret
我们用的时候只需这样就可以了:
RuleEngine('config_file').eval()
具体应用的需求就看我们进一步如何改进了。后面有时间写一个增强版本的,现在功能还是太弱了。
规则的定义
我们希望定义的规则如下:
(define a 1)
(define b 2)
(define c 4)
(and a b)
(define f (lambda (x)) (* x x))
(and (eq (f 2) c))
看起来真的非常的强大,如果我们实现了增强的版本就能做到这样的功能。