Some doubts related about how work a meaning predicate that interprets the parse tree of a DCG grammar in Prolog

StackOverflow https://stackoverflow.com/questions/16593662

  •  29-05-2022
  •  | 
  •  

Question

I am studying Prolog DCG grammar* and **parse tree on the Ivan Bratko book: "Programming for Artificial Intelligence"

I am finding some difficulties with the following example that provide a DCG grammar that create a parse tree from a string that belong to the defined language.

The defined language is a list of moves of a robotic arm that can be only of two type: up and down so [up,up,down,up,up] belongs to the language defined by my DCG grammar.

The program provide also a meaning/2 predicate that interprets the parse tree associated with a certain string and that mean the distance crossed by robot arm (Whereas it is associated with a move up the value +1, and the value -1 to a move down)

So for example for the list [up,up,down,up,up], the mean/2 predicate calculate a +3 distance

This is the code of my example (work well):

move(move(Step)) --> step(Step).
move(move(Step, Move)) --> step(Step), move(Move).

step(step(up)) --> [up].
step(step(down)) --> [down].

/* Take the parse tree of a string that belong to the language defined by the DCC grammar and
   calculate the total distance whereas that an up move give a +1 distance and a down move
   give -1 distance
*/
meaning(move(Step, Move), Dist):- 
                                  /* Calculate the distance given by the current step node 
                                     (which can be +1 or -1) */
                  meaning(Step, D1),
                  /* Calculate the distance given by the current moove node
                                     (which must be calculated recursively on a subtree having 
                                      a moove node as root */
                  meaning(Move, D2),
                  /* The final distance series of moves is the distance of the
                                     current step + the distance diven from the moves in the
                                     moove subtree */
                  Dist is (D1 + D2).

meaning(step(Step), Dist):- meaning(Step, Dist).
meaning(move(Step), Dist):- meaning(Step, Dist).

% step(up) means that the distance is +1
meaning(step(up), 1).

% step(down) means that the distance is -1
meaning(step(down), -1).

So I have the meaning/2 predicate that take a parse tree and calculate the total distance of the moves.

So I have 2 BASE CASE that rappresent the distance value associated to a single move (to a step), that can be +1 for the up step and -1 for the down step:

meaning(step(up), 1).
meaning(step(down), -1).

The meaning/2 take a parse tree that, as defined by the DCG grammar, have a move node as root: this root will have a left child that is a step node (so it is a single move, so it have a specific distance +1 or -1 associated to it) and a right child that is a move node (so it rappresent another subtree)

So the total distance is the sum of the distance of the current step that is +1 or -1 (the left child of the current move root) + the distance in right subtree.

I think that this is correct and this is pretty clear for me

The thing that I don't understand is what represent to me these two predicates in the code:

meaning(step(Step), Dist):- meaning(Step, Dist).
meaning(move(Step), Dist):- meaning(Step, Dist).

I can not stick them in my reasoning :-(

Was it helpful?

Solution

We use these rules like so,

4 ?- phrase(move(X), [up,up,down,up,up]).
X = move(step(up), move(step(up), move(step(down), move(step(up), 
      move(step(up)))))) ;
false.

5 ?- meaning($X,N).
N = 3 ;
false.

The term produced is highly nested:

move(step(up),                           % move/2: step/1 , 
     move(step(up),                      %   move/2: step/1 ,
          move(step(down),               %     move/2: step/1 ,
               move(step(up),            %       move/2: step/1 ,
                    move(step(up))))))   %         move/1: step/1 .

The code that you ask about, strips away the functors from the compound terms, getting to the "meat" of it, i.e. up or down atom arguments:

(2) meaning(step(Step), Dist):- meaning(Step, Dist).

"to find the ''meaning'' of a unary compound term step(X), is the same as to find the ''meaning'' of X".

(3) meaning(move(Step), Dist):- meaning(Step, Dist).

"to find the ''meaning'' of a unary compound term move(X), is the same as to find the ''meaning'' of X".

(4) base cases: ''meaning'' is given as 1 or -1 for up or down atoms.

meaning(step(up), 1).                    % clashes with rule (2)
meaning(step(down), -1).                 % clashes with rule (2)

(1) And the main case deals with binary compound terms with the functor move:

meaning(move(Step, Move), Dist):- 
    meaning(Step, D1),
    meaning(Move, D2),
    Dist is (D1 + D2).

move/2 is a custom version of (non-empty) list, '.'/2, actually:

1 ?- write_canonical([1,2,3]).
'.'(1,'.'(2,'.'(3,[])))
true.

2 ?- write_canonical([step(up),step(down),step(up)]).
'.'(step(up),'.'(step(down),'.'(step(up),[])))
true.

And meaning/2 is a fold.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top