【问题标题】:Constraint definition language约束定义语言
【发布时间】:2018-03-31 09:05:07
【问题描述】:

我需要设计一种基于如下定义强制执行约束的语言。下面的清单是brat 的实际注释配置。我的任务是为我们的内部工具设计一种用于类似目的的语言。我也打算用python写解析器。

[entities]
Drug
DrugClass
Procedure
Therapy
AE
SAE
Disease

[relations]
Equiv   Arg1:<ENTITY>, Arg2:<ENTITY>, <REL-TYPE>:symmetric-transitive

BelongsTo   Arg1:Drug         , Arg2:DrugClass
BelongsTo   Arg1:AE           , Arg2:AE
BelongsTo   Arg1:AE           , Arg2:SAE
BelongsTo   Arg1:SAE          , Arg2:SAE
BelongsTo   Arg1:SAE          , Arg2:AE
BelongsTo   Arg1:Disease      , Arg2:Disease
BelongsTo   Arg1:Drug         , Arg2:Therapy
BelongsTo   Arg1:Procedure    , Arg2:Therapy
BelongsTo   Arg1:Surgery      , Arg2:Therapy

<CAUSE>=Drug|DrugClass|Therapy|Procedure
<EV>=AE|SAE

AssociatedWith      Arg1:<CAUSE>    , Arg2:<EV>
NotAssociatedWith   Arg1:<CAUSE>    , Arg2:<EV>

Causes          Arg1:<CAUSE>    , Arg2:<EV>
NotCauses       Arg1:<CAUSE>    , Arg2:<EV>

HasEffect       Arg1:<CAUSE>    , Arg2:Disease
HasNoEffect     Arg1:<CAUSE>    , Arg2:Disease

<OVERLAP>   Arg1:<ANY>, Arg2:<ANY>, <OVL-TYPE>:<ANY>

我想到的是以下内容。

[entities]
# subtyping entities which is already present in brat
Entity
  Trigger
    Drug
    DrugClass
    Procedure
    Therapy
  Effect
    AE
    SAE
    Disease

[relations]
# Any subtype of Trigger can be Associated with any subtype of Effect except Disease    
AssociatedWith  Arg1:Trigger    , Arg2:Effect.except(Disease)
NotAssociatedWith   Arg1:Trigger    , Arg2:Effect.except(Disease)

Causes      Arg1:Trigger    , Arg2:Effect.except(Disease)
NotCauses       Arg1:Trigger    , Arg2:Effect.except(Disease)

HasEffect       Arg1:Trigger    , Arg2:Disease
HasNoEffect     Arg1:Trigger    , Arg2:Disease

# Equiv relation can exist between Drug and Drug,
# DrugClass and DrugClass and so on,
# but not between different subtypes Drug and AE
Equiv   Arg1:Entity*          , Arg2: Entity*      

BelongsTo   Arg1:Entity*          , Arg2: Entity*      
BelongsTo   Arg1:Drug         , Arg2:Therapy
BelongsTo   Arg1:Procedure        , Arg2:Therapy
BelongsTo   Arg1:Surgery          , Arg2:Therapy

<OVERLAP>   Arg1:<ANY>, Arg2:<ANY>, <OVL-TYPE>:<ANY>

是否已经有一种语言可以做到这一点。我研究了 Prolog,这似乎是一种矫枉过正。我想我正在寻找一种可以处理对象分组和粒度寻址的语言,以便可以简洁地指定约束。谢谢

【问题讨论】:

    标签: python-3.x configuration data-annotations constraint-programming


    【解决方案1】:

    更容易思考的是,这些定义在解析后会如何在内存中 - 然后向后工作。一种简单的解析方法是将每一行视为“方法调用” - 例如“BelongsTo Arg1:Drug”可以看作是对 ParserContext 对象的隐式“this.BelongsTo”方法调用。所以你基本上用 ParserContext 类“评估”文件,文件中的每一行“静默”地调用基类上的方法,慢慢地建立 in-memory 。当最后一行完成时,内存中的定义也完成了。

    在 Ruby 中,不需要在方法和“this”周围加上括号。是隐含的(就像在大多数其他语言中一样)。所以,你认为的 DSL/语言只是 Ruby 中的纯代码。

    让我们来一个简单的 Parser 类。

    class Context
      def new
        # initialize some vars
        this.entities = {}
      end
    
      def Entity(name, ...args)
        # save to 
        self.entities[name] = ...args
      end
    
      def BelongsTo(entity, ...args)
        # process belongs to with the entity
      end
    
      ... every DSL feature is a language method ...
      ... if you want to "zoom-in" or focus on an entity, use blocks
    

    让我们采用以下 DSL...

    Entity "Arg1"
    BelongsTo "Arg2"
    

    还有这个简单的阅读器:

    ctx = Context.new
    ctx.instance_eval File.read "my dsl file"
    

    所以 DSL 文件只是在将“this”设置为上下文对象的情况下进行评估,并且 DSL 中的每一行都只是简单的方法调用。 Ruby 中的 Gemfile、Rails 中的 Routes 文件、许多 ORM 定义等 - 一直使用这个技巧。 看起来像 DSL 的只是漂亮的代码。作为一个关于 Ruby 的简单示例 - https://github.com/rdsubhas/ruby-blocks/blob/master/Mapping - 你会看到虽然它看起来像一个 DSL,但它实际上只是代码,并且实际上 没有解析器 参与解析该代码。语言本身会解析它。

    这不仅适用于 Ruby,每种语言都有自己的“评估”技巧。我相信 nodejs 也可以做到这一点(茉莉花/黄瓜测试)。

    希望能回答您的问题。总结一下:

    • 看看它在解析后后在内存中的样子
    • 为 DSL 反向工作
    • 使用语言解析器

    旁注:您展示的 DSL 看起来很复杂,以至于业务/产品人员不容易使用。看起来它是为开发人员或高级用户准备的。所以不要对 DSL 施加自我约束,比如它必须有括号,或者它不能有双引号之类的东西。当这适用于高级用户时,引号或括号的使用将不再重要。选择一个对你来说最省力的。

    【讨论】:

      猜你喜欢
      • 2014-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多