【问题标题】:How can I create this DCG in Prolog?如何在 Prolog 中创建这个 DCG?
【发布时间】:2016-04-23 22:40:27
【问题描述】:

我想创建一个 DCG,这样的语言可以被接受:

  • c
  • bbbcbbb
  • bbacbba
  • 蕉麻
  • aababacaababa

如您所见,这意味着 a 和 b 有一个特定的顺序,然后是一个 c,然后又是与 c 之前完全相同的顺序。如果不满足这些条件,它将失败。

我目前正在这里使用我的方法(有效,但也能识别错误的单词)

s --> x, s, x. 
s --> [c]. 
x --> [a]. 
x --> [b]. 

你们中的任何人可以帮我解决我需要改变的地方吗?我不知道怎么继续。非常感谢。

【问题讨论】:

    标签: prolog regular-language dcg


    【解决方案1】:

    DCG 实际上只是一个 Prolog 程序,经过预处理添加实现差异列表的隐藏参数。我们总是可以添加自己的参数,并使用模式匹配。那么

    s --> ab(X), [c], ab(X). 
    ab([a|T]) --> [a], ab(T).
    ab([b|T]) --> [b], ab(T).
    ab([]) --> [].
    
    ?- atom_chars(aababacaababa,Cs),phrase(s, Cs).
    Cs = [a, a, b, a, b, a, c, a, a|...] 
    

    【讨论】:

      【解决方案2】:

      您所描述的语言既不是常规的,也不是上下文无关的。因此,您需要求助于 DCG 中提供的 Prolog 扩展。您可能会习惯一些成语:

      % any sequence
      
      seq([]) -->
         [].
      seq([E|Es]) -->
         [E],
         seq(Es).
      

      使用这个非终结符,我们可以描述一个重复并由一个字符分隔的序列:

      rep(Seq, Sep) --> 
         seq(Seq),
         [Sep],
         seq(Seq).
      

      这显然太笼统了。你只想要abc。您现在可以添加更多要求:

      rep(Seq, Sep) -->
         seq(Seq),
         {phrase(abs,Seq)},
         [Sep],
         seq(Seq).
      
       abs --> [] | ("a"|"b"), abs.
      

      那么现在:

       s -->
           rep(_,c).
      

      另一种方法是“硬编码”语法,正如@CapelliC 所示。使用seq//1 使该方法更加灵活。

      在字符列表中使用双引号非常方便。 请参阅this answer 如何允许使用双引号来表示字符列表。

      【讨论】:

      • 这个设计也很好地通过phrase(s, L).生成解决方案
      • @mbratch:这更多的是运气而不是意图。查看所有解决方案的规范方法是?- length(L, N), phrase(s, L).。现在,它们也按长度排序。见,stackoverflow.com/questions/6524722/…
      • 左撇子戈麦斯说,“我宁愿幸运也不要善良。” ;) 但无论如何,上面的代码按长度顺序生成“a,b”序列,并在继续下一个长度之前完成每个长度的排列集,这是一个很好的意外。我还在学习 DCG 的许多细微差别,所以这篇文章和 @CapelliC 的帖子对我来说都非常有启发性。
      • @mbratch:这里有两个不同的概念:终止(意味着通用终止)和公平枚举。如果发生冲突,请务必终止。以所有固定长度终止的 DCG 可以简单地用于枚举所有句子。但反之则不然。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多