【问题标题】:Prolog+clpfd: simple binary number parser with valueProlog+clpfd:带值的简单二进制数解析器
【发布时间】:2015-05-20 05:09:29
【问题描述】:

我目前正在尝试理解 prolog 中的 DCG。

考虑这个例子。

digit(0) --> "0".
digit(1) --> "1".

binaryNumber(Val) --> digit(Val).

binaryNumber(Next*2 + Cur) -->
    %CurVal #= Cur + Next*2,
    binaryNumber(Next),
    digit(Cur).

产生:

207 ?- binaryNumber(X, Y, []).
X = 0,
Y = [48] ;
X = 1,
Y = [49] ;
X = 0*2+0,
Y = [48, 48] ;
X = 0*2+1,
Y = [48, 49] ;
X = 1*2+0,
Y = [49, 48] ;
X = 1*2+1,
Y = [49, 49] ;
X = (0*2+0)*2+0,

这很好。

但是,如果我想将字符串“转换”为值:

:- use_module(library(clpfd)).

digit(0) --> "0".
digit(1) --> "1".

binaryNumber(Val) --> digit(Val).

binaryNumber(CurVal) -->
    CurVal #= Cur + Next*2,
    binaryNumber(Next),
    digit(Cur).

我明白了:

209 ?- binaryNumber(X, Y, []).
X = 0,
Y = [48] ;
X = 1,
Y = [49] ;
ERROR: binaryNumber/3: Undefined procedure: (#=)/4
ERROR:   However, there are definitions for:
ERROR:         (#=)/2
   Exception: (7) #=(_G4807345, _G4807428+_G4807431*2, _G4807346, _G4807475) ? 

...

两个问题:

  1. 为什么binaryNumber 想要#= 的“arity”为4?
  2. 我该如何解决这个问题?

【问题讨论】:

  • @false:如果您对此感兴趣,该示例是合成的,用于训练。 IE。我对“如何将字符串转换为数字”不感兴趣,但对“如何在 prolog 中使用 dcgs 作为解析器”感兴趣。
  • 但 DCG 正是在这里将某物列表“转换”为其他东西 - 反之亦然。
  • @false:意思是说对于字符串数字转换,通常有实用函数。所以其他人可能一直在寻找那个功能,而我正在寻找对 dcgs 的理解。有点不同的问题......

标签: prolog dcg clpfd


【解决方案1】:

非常接近了!

通常,foo//n 不是“直接”实现的,而是通过将语法 foo//n 转换为相应的 Prolog 谓词 foo//(n+2) 来实现的。此翻译由term_expansion/2 完成,这是一种类似于其他语言中的宏的机制。通常,您根本不必介意。


有关 的更多信息,请阅读:(1) this DCG primer,和 (2) 问题 “Is there a way or an algorithm to convert DCG into normal definite clauses in Prolog?”以及该问题的答案。


回到主题,我在您的 使用中看到两个 问题:

  1. 如果在语法规则中使用,“普通”Prolog goals 必须用大括号 {}/1 封装, 所以它们在前面提到的“语法到谓词”翻译步骤中被跳过。在您的代码中,您不想使用(#=)//2(又名(#=)/4),您需要(#=)/2

  2. 这是很好的做法,直接使用foo/(n+2) 目标。 为此使用phrase/2phrase/3

那么我们来编辑对应的代码sn-p:

binaryNumber(Next*10 + Cur) -->
    { CurVal #= Cur + Next*2 },
    binaryNumber(Next),
    digit(Cur).

现在我们来查询吧!

?- phrase(binaryNumber(X),Ts).
X = 0, Ts = [48]    ;
X = 1, Ts = [49]    ;
X = 0, Ts = [48,48] ;
X = 1, Ts = [48,49] ;
X = 2, Ts = [49,48] ;
X = 3, Ts = [49,49] ...

【讨论】:

  • @SigTerm。尝试在第二个子句中更改digitbinaryNumber 的顺序。如果您使用新版本的 SWI-Prolog,请确保使用“--traditional”选项启动它!
  • @repeat:好的,很公平。如果我仍然需要解决该问题的帮助,我将发布新问题(我可以肯定我可以通过引入“中间人”谓词来反转字符串)。感谢您的帮助/玩得开心。
  • @repeat:在这个例子中,评论会更好。也就是说,如果它可以用 cmets 表示到更好的结果,请使用 cmets。在failure-slice 中,我确实使用了<b><s>,但是如果不使用它们,代码的可读性会降低,并且使用cmets 会更加庞大。
  • binaryNumber//1 的终止对我来说似乎并没有终止。 (我没有看细节,我只是错过了对变量的一些合理限制)。
  • @mat:这种突出显示经常被“编辑”删除。很难证明将其用于failure-slice 是合理的,但在这种情况下几乎是不可能的(这与其他编程语言非常相似)。
猜你喜欢
  • 2016-01-16
  • 1970-01-01
  • 1970-01-01
  • 2013-07-08
  • 2012-06-28
  • 2011-11-23
  • 2014-11-12
  • 1970-01-01
  • 2016-09-03
相关资源
最近更新 更多