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

时间:2015-05-20 05:09:30

标签: prolog dcg clpfd

我目前正试图了解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. 我该如何解决这个问题?

1 个答案:

答案 0 :(得分:4)

非常关闭!

通常, NSDictionary并非“直接”实现,而是通过将语法foo//n翻译为相应的Prolog谓词foo//n。此翻译由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 目标必须用大括号foo//(n+2)封装, 所以他们在前面提到的“语法到谓词”翻译步骤中被跳过了。在您的代码中,您不想使用{}/1(a.k.a。(#=)//2),您想要(#=)/4

  2. 优良作法,直接使用(#=)/2目标。 请使用phrase/2phrase/3

  3. 让我们编辑相应的代码段:

    foo/(n+2)

    现在让我们查询!

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