将布尔表达式表示为有限状态机

时间:2016-06-08 07:35:30

标签: boolean fsm

是否可以将布尔表达式表示为有限状态机,以便FSM接受与布尔表达式匹配的输入?

是否有可能合并多个此类FSM,并在接受时,知道哪个原始FSM匹配?

背景:我正在尝试一次评估很多布尔表达式。我认为用正确的表示法,也许DFA可以超级有效地做到这一点(即优于O(n),其中n =表达式数。)

1 个答案:

答案 0 :(得分:0)

我知道这是一个非常老的问题,但我确实发现自己处于类似情况,并且我认为在某些情况下,FSM可能会为复杂的布尔逻辑提供帮助。

我在blog post of mine中概述了一个示例,其中描述了在遍历(循环)简单字符串的令牌时使用状态机的情况。

在这种情况下的优点是,解析过程中的每个令牌都没有专用的布尔标志,而语法树中的其他路径需要防范,我可以将每个令牌作为事件提供给FSM并让机器陷入不同的状态。在处理状态时,我使用Statechart操作来构建少量操作码,然后最终根据最终状态放弃或继续编译生成的操作码。

您必须阅读这篇文章,才能获得我上面所说的内容。但要点是,在某些情况下,可以将一系列布尔值转换为事件名称,然后传递给FSM进行处理。在另一个示例中,我不得不根据一组压倒性的布尔逻辑来选择需要呈现的UI状态。

由于某些标志优先于其他标志,因此生成的逻辑树如下所示:

图1 —示例UML活动图

UML Activity diagram

产生的代码看起来像这样:

图2 —复杂的布尔逻辑代码
let presenterFlags = {
  showSpecialTypeTab: model.type === 'special',
  showDefaultWarning: (model.type === 'special' && model.isDefault && !settings.enforced),
  showDefaultInBrokenStateWarning: (model.type === 'special' && model.isDefault && settings.enforce),
  disableSaveButton: (model.type === 'special' && model.isDefault && !settings.enforce) || !model.canWrite,
  disableCancelButton: (model.type === 'special' && model.isDefault && !settings.enforce) || !model.canWrite,
  disableDeleteButton: (model.type === 'special' && model.isDefault) || !model.canWrite,
  disableEnforcementToggle: (model.type === 'special' && model.isDefault && !settings.enforced) || !model.canWrite,
  disableAnotherToggle: (model.type === 'special' && model.isDefault) || !model.canWrite,
};

对我来说,我的大脑承受不了太多。因此,我依靠使用FSM生成了如下状态图:

图3 —示例UML状态图

UML State diagram

使用XState的代码可能看起来像这样:

图4 — XState机器示例
let booleanMachine = Machine({
  id: 'ExamplePresentationFlags',
  strict: true,
  initial: 'conditional',
  context: {},
  states: {
    conditional: {
      on: {
        'EVALUATE': [
          { target: 'SpecialExample', cond: 'isSpecialExample' },
          { target: 'GenaricExample' },
        ],
      },
    },
    GenaricExample: {
      initial: 'conditional',
      states: {
        conditional: {
          on: {
            '': [
              { target: 'ReadOnly', cond: 'canNotWrite' },
              { target: 'Default', cond: 'isDefault' },
              { target: 'Writable' },
            ],
          },
        },
        Writable: {},
        Default: {},
        ReadOnly: {
          meta: {
            disableSaveButton: true,
            disableCancelButton: true,
            disableDeleteButton: true,
          },
        },
      },
    },
    SpecialExample: {
      initial: 'conditional',
      meta: { showSpecialTypeTab: true },
      states: {
        conditional: {
          on: {
            '': [
              { target: 'ReadOnly', cond: 'canNotWrite' },
              { target: 'Default', cond: 'isDefault' },
              { target: 'Writable' },
            ],
          },
        },
        Writable: {},
        ReadOnly: {
          meta: {
            disableSaveButton: true,
            disableCancelButton: true,
            disableDeleteButton: true,
            disableAnotherToggle: true,
          },
        },
        Default: {
          initial: 'conditional',
          states: {
            conditional: {
              on: {
                '': [
                  { target: 'Enforced', cond: 'isEnforced' },
                  { target: 'Unenforced' },
                ],
              },
            },
            Unenforced: {
              meta: {
                exampleWarning: 'default-read-only',
                disableSaveButton: true,
                disableCancelButton: true,
                disableDeleteButton: true,
                disableAnotherToggle: true,
              },
            },
            Enforced: {
              meta: {
                exampleWarning: 'special-default-broken-enforce-state',
                disableSaveButton: false,
                disableCancelButton: false,
                disableDeleteButton: true,
                disableAnotherToggle: true,
              },
            },
          },
        },
      },
    },
  },
}, {
  guards: {
    isSpecialExample: (ctx) => ctx.exampleType === 'special',
    canNotWrite: (ctx) => !ctx.canWrite,
    isEnforced: (ctx) => ctx.isEnforced,
    isDefault: (ctx) => ctx.isDefault,
    isNotDefault: (ctx) => !ctx.isDefault,
  },
});

具有类似reducer的功能:

图5 — XState reducer函数示例
function presentorFlags({ canWrite, model, settings }) {
  let machine = booleanMachine.withContext({
    canWrite,
    exampleType: model.type,
    isEnforced: settings.enforced,
    isDefault: model.isDefault,
  });
  let { meta } = machine.transition(machine.initialState, 'EVALUATE');
  return Object.keys(meta)
    .reduce((acc, key) => ({ ...acc, ...meta[key] }), {});
}

理解我同意这个例子是非常规的,而且也更大。它的确为我提供了理解逻辑的能力,尤其是借助手头的可视化工具(即图3)。当时,它使我可以概念化所有边缘情况状态,而不必担心就视图代码而言,UI的每个状态意味着什么。相反,我可以专注于状态本身以及什么逻辑可使计算机进入该状态。然后,我给了reducer实际的布尔值,然后让机器完成了工作。我得到的只是一组易于放置在模板中的UI标志。

再次,也许这不是更好,或者也许是。关键是使用状态机来表达布尔逻辑是可能的