Prolog - creating a recursive list

for a program I am writing, I need to make a list of lists with pairs of numbers representing the product and the sum of two given numbers.

Now I have a function that I can specify how many times I want to add the list to the list, which will later be expanded with full functionality.

Here's what I have:

s1(0, X).
s1(Q, X) :-
    N is Q - 1,
    multiply(2, 3, Y),
    A = Y ,
    add(2, 3, Z),
    B = Z,
    addToEnd([A], [B], X),
    s1(N,X).

multiply(A, B, C):-
    C is A * B.

add(A, B, C) :-
    C is A + B.

addToEnd([], L, L).
addToEnd([H|T], L2, [H|L3]) :-
    addToEnd(T, L2, L3).

      

However, when I run s1(2,X)

, for example, I return [6,5]

and then nothing else, it just hangs. When I run s1(0,X)

I get true

, then false

when I press;

Can anyone help me with this? I can't see what I am doing wrong, I feel like it should work!

To understand how I believe this should work: I am calling s1(2,X).

N = 1

, [6,5]

added to list X([[6,5]])

s1(1,X).

N=0

, [6,5]

added to list inX ([[6,5],[6,5]])

s1(0,X).

X = [[6,5],[6,5]]

+3


source to share


1 answer


So there are many things here. First of all, as with most declarative languages, a variable cannot actually change its value.

This means it will X = 1.

unify 1

before X

, as you would expect, but if you add X = 2.

after that to your query ( X = 1, X = 2.

), Prolog will say false

, The reason is that you cannot merge 1

with 2

and that X

really has become 1

, therefore X

it cannot be unified before 2

.

Although this is different from Haskell, Ocaml, etc., you can bind a partial variable as in X = h(Y).

. Then you can unify it even more X = h(a(Z)).

, while you couldn't in the languages ​​mentioned earlier (where the variable is actually just an alias for the value).

Why does he tell me everything that interests you? Well, that's your main problem here. First you bind X

to [6, 5]

and then you await further bindings to other things. When a variable is grounded (ie, does not contain any free variable within it), you can never change its value again.

So your recursion won't do anything, but it will prove X

false in the end . This is not the case here, as you end up calling addToEnd/3

with the same arguments every time ( [6]

, [5]

and [6, 5]

).

Speaking of which, let's see how we can improve your code.

First, a note:

multiply(2, 3, Y),
A = Y ,
add(2, 3, Z),
B = Z,
addToEnd([A], [B], X),

      

can be written

multiply(2, 3, Y),
add(2, 3, Z),
addToEnd([Y], [Z], X),

      

without losing information, since you don't use A

and again B

.

Now, forget about addToEnd/3

for a moment and think about what you want.

If you enter s1(0, Q)

, do you really want to Q

stay free? Because what you are claiming at the moment. In this case, it would be more appropriate to bind Q

to []

. Also, it will do a nice recursive base case, as you'll see shortly.

s1(0, []).

      

is a shortcut to say

s1(0, Q) :- Q = [].

      



as Prolog does unification in clause chapters (part before :-

).

Then I'm cheating a little, but I'll just stay clean. You can indicate that when going from s1(4, Q)

to, s1(5, Q)

you expect Q to hold another value of some calculus.

Here we could argue that as follows:

s1(N, [SomeCalculus|Q]) :-
    PreviousN is N - 1,
    s1(PreviousN, Q).

      

Now we need to provide a value SomeCalculus

:

s1(N, [SomeCalculus|Q]) :-
    PreviousN is N - 1,
    X is 2 * 3,
    Y is 2 + 3,
    SomeCalculus = [X, Y],
    s1(PreviousN, Q).

      

or, if you followed correctly, we could write:

s1(N, [[X, Y]|Q]) :-
    PreviousN is N - 1,
    X is 2 * 3,
    Y is 2 + 3,
    s1(PreviousN, Q).

      

So the complete program would be:

s1(0, []).
s1(N, [[X, Y]|Q]) :-
    PreviousN is N - 1,
    X is 2 * 3,
    Y is 2 + 3,
    s1(PreviousN, Q).

      

Now, if you check this, you may notice that the program is singing just like yours when you press a key ;

. This is because Prolog thinks the second clause can apply to 0

 too.

So let's edit the program again:

s1(0, []).
s1(N, [[X, Y]|Q]) :-
    N > 0,
    PreviousN is N - 1,
    X is 2 * 3,
    Y is 2 + 3,
    s1(PreviousN, Q).

      

Now everything is all right.

Hopefully this will help you better understand how to construct a correct predicate through recursion. I didn't spend a lot of time fixing your predicate addToEnd/3

, because my incoherent relationship to variables should already tell you a lot about what is wrong with it.

+5


source







All Articles