规则引擎的设计和实现(一)

Table of Contents


先占坑,有时间再加注释和改进,然后写一下如何应用。

规则引擎是什么

一个简单的实现

我们的配置文件长啥样呢

(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))

看起来真的非常的强大,如果我们实现了增强的版本就能做到这样的功能。

问题