I'm currently trying to understand DCGs in prolog.
Consider this example.
digit(0) --> "0".
digit(1) --> "1".
binaryNumber(Val) --> digit(Val).
binaryNumber(Next*2 + Cur) -->
%CurVal #= Cur + Next*2,
binaryNumber(Next),
digit(Cur).
That produces:
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,
Which is nice.
However, if I want to "convert" string to value:
:- use_module(library(clpfd)).
digit(0) --> "0".
digit(1) --> "1".
binaryNumber(Val) --> digit(Val).
binaryNumber(CurVal) -->
CurVal #= Cur + Next*2,
binaryNumber(Next),
digit(Cur).
I get:
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) ?
...
Two questions:
binaryNumber
want #=
to have "arity" of 4? You're very close!
Commonly, a 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
, a mechanism analogous to macros in other languages. Usually, you don't have to mind it at all.
For more on dcg read: (1) this DCG primer, and (2) the question "Is there a way or an algorithm to convert DCG into normal definite clauses in Prolog?" and the answers to that question.
Coming back to the subject, I see two issues in your dcg use:
If used within grammar rules, "ordinary" Prolog goals must be encapsulated with curly braces {}/1
,
so they are skipped in aforementioned "grammar to predicate" translation step. In your code, you don't want to use (#=)//2
(a.k.a. (#=)/4
), you want (#=)/2
!
It is good practise, not to use foo/(n+2)
goals directly.
Use phrase/2
or phrase/3
for that!
So let's edit the corresponding code snippet:
binaryNumber(Next*10 + Cur) -->
{ CurVal #= Cur + Next*2 },
binaryNumber(Next),
digit(Cur).
Now let's query!
?- 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] ...