Prolog+clpfd:带值的简单二进制数解析器

Prolog+clpfd: simple binary number parser with value

我目前正在尝试理解 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,

这很好。

但是,如果我想 "convert" 字符串值:

:- 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. 我该如何解决这个问题?

非常接近!

通常是 foo//n isn't implemented "directly", but by translating a grammar foo//n to a corresponding Prolog predicate foo//(n+2). This translation is done by term_expansion/2,一种类似于其他语言中的宏的机制。通常情况下,你完全不必介意。


有关 read: (1) this DCG primer 的更多信息,以及 (2) 问题 “”以及该问题的答案。


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

  1. 如果在语法规则内使用,"ordinary"Prolog goals必须用花括号{}/1封装, 因此在上述 "grammar to predicate" 翻译步骤中会跳过它们。在你的代码中,你不想使用 (#=)//2 (a.k.a. (#=)/4),你想要 (#=)/2!

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

那么让我们编辑相应的代码片段:

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] ...