使用F#构建高度可调试的业务规则引擎

时间:2014-07-20 17:49:43

标签: f# business-rules quotations

问题

我在F#中有代表逻辑树的代码。它是一个业务规则引擎,具有一些相当简单的数学函数。我希望能够多次运行树的规则,并查看通过树的每条特定路线的次数。

要求是基本规则不应该从我目前使用的简单匹配语句中改变太多。使用属性标记重要函数会很好,但是在每个节点上添加对日志记录函数的调用则不行。我希望能够以两种模式运行代码,一种高性能的标准模式,它只给出答案,然后是一种“探索模式”,它提供了每次调用背后的更多细节。虽然我不介意动态加载和分析规则的复杂代码,但规则代码本身必须看起来很简单。理想情况下,我不想依赖第三方库 - powerpack还可以。该解决方案还必须以.NET 4.0运行时为目标。

潜在解决方案

  1. 使用函数名和参数为每个函数添加日志记录调用。我不喜欢这样,因为即使我可以在某种释放模式下禁用它,它仍然会使规则混乱,并且意味着所有新代码都必须以不自然的方式编写。

  2. 每个函数返回其结果,然后返回一个列表,其中包含目前调用的方法的名称。我不喜欢这样,因为它看起来不自然,会带来性能损失。我确信我可以使用计算表达式来完成大量的管道工作,但这违反了保持规则简单的要求。

  3. 使用引号解析规则树,然后构建一个新表达式,该表达式是一个旧表达式,调用注入每个标记函数站点的日志记录函数。这是我到目前为止所做的最好的事情,但我担心编译结果报价所以我可以运行它。我理解(请纠正我,如果我错了)并非所有报价都可以编译。我宁愿没有一个不稳定的过程将规则代码限制为F#语言的一个子集。如果规则编译,我希望我的解决方案能够处理它们。

  4. 我知道这是一个非常严格要求的难题,但如果有人对解决方案有任何启发,我将非常感激。

    编辑:只是举例说明我可能正在使用的那种规则,如果我拥有一个生产产品A和B的小工具工厂,则可能会使用以下简单代码。我不希望通过使用辅助函数和钩子装饰该层来丢失公式的可读性和简单性。

    type ProductType = | ProductA | ProductB
    
    let costOfA quantity =
        100.0 * quantity
    
    let costOfB quantity =
        if quantity < 100.0 then
            20.0 * quantity
        else
            15.0 * quantity
    
    let calculateCostOfProduct productType quantity =
        match productType with
        | ProductA -> costOfA quantity
        | ProductB -> costOfB quantity
    

0 个答案:

没有答案