1
votes

I'm a beginner in Prolog, so I'm still confused on how to form a recursive function in Prolog.

Let say I have a matrix:

S: 
[ 5   6 
  3   4 ] 

Represented in prolog as: S = [ [5,6], [3,4]].

I'm trying to write a recursive function to get a cell value such that cell_values (Cells, Matrix, Values) would return a list of the values from a list of the cell.

Example: cell_values ([[0,0], [0,1]], S, Values) --> Values = [5, 6]. Where S is the matrix above.

I'm thinking of using nth0 to get the value. This is my work so far.

:- use_module(library(clpfd)).

cell_values([], [], []).
cell_values([X|T], S, Values) :- 
    nth0(X, S, Row),
    nth0(T, Row, Values).

Not sure how to fix this. Can you point me in the right direction?

1
Hint: if the first parameter is a list of 2-tuple with the dimensions, then how should the pattern look like? - Willem Van Onsem

1 Answers

2
votes

There are some problems here with the predicate:

  1. you use S and T as row number and column number, but S is the head of the list, and T the tail here. Since the list of indices is a list of lists, that means S will be a list, and T a list of lists;
  2. you do not use recursion to generate a list of values, so if we fix the above, then it will still - at most - yield a specific value; and
  3. the base predicate is too restrictive, since it assumes that the matrix (the second parameter), should be empty. This does not makes sense, since normally the matrix will be passed without any changes. Regardless of the matrix, if the list of indices is empty, then so is the list of values.

explicit recursion

So if we rewrite the predicate, there are two rules:

  1. the base case: in case the list of indices is empty, then regardless of the matrix, the list of values is empty as well:

    cell_values([], _, []).
    
  2. in the recursive cass, we match the first list with [[R, C] | T], so R is the row number, and C the column number, T is the list of remaining lists to process, so we perform the nth0/3 as demonstrated in the question, but with R and C, and the cell value V is prepended to the result list [V|VT], the VT is then used in the recursive call to obtain more elements:

    cell_values([[R, C]| T], M, [V|VT]) :-
        nth0(R, M, Row),
        nth0(C, Row, V),
        cell_values(T, M, VT).
    

Or putting these together:

cell_values([], _, []).
cell_values([[R, C]| T], M, [V|VT]) :-
    nth0(R, M, Row),
    nth0(C, Row, V),
    cell_values(T, M, VT).

maplist/3

Processing lists is a rather common thing to do, so we might be interested in using maplist/3, and write a predicate that only processes a single sublist, like:

cell_value(M, [R, C], V) :-
    nth0(R, M, Row),
    nth0(C, Row, V).

Then we can define the predicate cell_values like:

cell_values(Ixs, M, Vs) :-
    maplist(cell_value(M), Ixs, Vs).