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) ?
...
两个问题:
- 为什么
binaryNumber
想要 #=
有 "arity" 4?
- 我该如何解决这个问题?
你非常接近!
通常是dcg 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
,一种类似于其他语言中的宏的机制。通常情况下,你完全不必介意。
有关 dcg read: (1) this DCG primer 的更多信息,以及 (2) 问题
“”以及该问题的答案。
回到主题,我在您的 dcg 使用中看到 两个 问题:
如果在语法规则内使用,"ordinary"Prolog goals必须用花括号{}/1
封装,
因此在上述 "grammar to predicate" 翻译步骤中会跳过它们。在你的代码中,你不想使用 (#=)//2
(a.k.a. (#=)/4
),你想要 (#=)/2
!
那么让我们编辑相应的代码片段:
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] ...
我目前正在尝试理解 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) ?
...
两个问题:
- 为什么
binaryNumber
想要#=
有 "arity" 4? - 我该如何解决这个问题?
你非常接近!
通常是dcg 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
,一种类似于其他语言中的宏的机制。通常情况下,你完全不必介意。
有关 dcg read: (1) this DCG primer 的更多信息,以及 (2) 问题
“
回到主题,我在您的 dcg 使用中看到 两个 问题:
如果在语法规则内使用,"ordinary"Prolog goals必须用花括号
{}/1
封装, 因此在上述 "grammar to predicate" 翻译步骤中会跳过它们。在你的代码中,你不想使用(#=)//2
(a.k.a.(#=)/4
),你想要(#=)/2
!
那么让我们编辑相应的代码片段:
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] ...