约束定义语言

时间:2018-03-31 09:05:08

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

我需要根据下面的定义设计一种强制约束的语言。下面的列表是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,这看起来像是一种矫枉过正。我想我正在寻找一种语言,它可以处理对象和粒度寻址的分组,从而可以简洁地指定约束。感谢

1 个答案:

答案 0 :(得分:1)

更容易思考,这些定义在解析后如何在内存中看起来像 - 然后向后工作。一种简单的解析方法是将每一行视为“方法调用” - 例如“BelongsTo Arg1:Drug”可以看作是对ParserContext对象的隐式“this.BelongsTo”方法调用。因此,您基本上使用ParserContext类“评估”文件,并且文件中的每一行“静默”调用基类上的方法,慢慢构建内存中的方法。当最后一行完成时,内存中的定义也已完成。

在Ruby中,人们不需要围绕方法的parantheses和“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"

因此,仅使用设置为上下文对象的“this”来评估DSL文件,并且DSL中的每一行都只是简单的方法调用。 Ruby中的Gemfile,Rails中的Routes文件,许多ORM定义等 - 一直使用这个技巧。 看起来像DSL一样只是漂亮的代码。作为Ruby上的一个简单示例 - https://github.com/rdsubhas/ruby-blocks/blob/master/Mapping - 您会看到虽然它看起来像DSL,但它实际上只是代码,并且实际上还有 no parser 来解析该代码。语言本身解析它。

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

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

  • 了解解析
  • 后内存的外观
  • 为DSL工作
  • 使用语言解析器

旁注:您展示的DSL看起来很复杂,不容易被商业/产品用户使用。看起来它适用于开发人员或高级用户。所以不要在DSL上设置自我约束,就像它必须有括号,或者它不能有双引号或那种东西。如果这是针对高级用户的,则引号或括号的使用将不再重要。选择一个最省力的人。