1

I wrote a program to sort numbers from symbols, and it works, but gives me a memory address at the end of the list that it didn't run through last. Why is that so?

separate([],[],[]).
separate([X],X,_):-number(X).
separate([X],_,X).
separate([X|Y],[X|Z],S):-number(X),separate(Y,Z,S).
separate([X|Y],Z,[X|S]):-separate(Y,Z,S).

When consulting with ?- separate([3,a,b,4,5,c],X,Y).

I get:

X = [3, 4, 5|_G2592],
Y = [a, b, c] .
false
  • 10,264
  • 13
  • 101
  • 209
Streamline
  • 63
  • 8
  • Instead of pressing `Enter` after seeing the answer, what happens if you press the space bar. See: [Why does SWI-Prolog only give me the first answer?](http://stackoverflow.com/q/34463248/1243762) – Guy Coder Jan 21 '17 at 17:59
  • It also helps when first learning Prolog not to use variables like `X` and `Y` but more meaningful names such as `Digit`, `Letter`, `Digits`, `Letters`, `Rest`. Once you understand what is happening then you can revert back to `X` and `Y`, etc. – Guy Coder Jan 21 '17 at 18:12

2 Answers2

2

I propose

separate([],[],[]).

separate([H | T], [H | Tn], Ls) :-
  number(H),
  separate(T, Tn, Ls).

separate([H | T], Ln, [H | Ts]) :-
  \+ number(H),
  separate(T, Ln, Ts).

If you have a terminal clause as separate([],[],[]) and a couple of ordinary clauses as separate([X|Y],[X|Z],S) and separate([X|Y],Z,[X|S]), you don't need semi-terminal clauses as separate([X],X,_) and separate([X],_,X) and they (with the undefined value _) avoid the unification of one of the lists and you get the "memory address" (the identifier of a not-unified variable).

And if you have a clause with number(X), the other (alternative) clause need the "not-number" check (that is \+ number(X)) otherwise both clauses are true with numbers and you multiply solutions, with numbers in the list of not numbers.

max66
  • 65,235
  • 10
  • 71
  • 111
1

That's because you leave your list tails open:

separate([X],X,_):-number(X).
separate([X],_,X).

The thing is: you actually do not need to write these statements, you could have omitted them:

separate([],[],[]).
separate([X|Y],[X|Z],S):-number(X),separate(Y,Z,S).
separate([X|Y],Z,[X|S]):-separate(Y,Z,S).

This would have worked but it would return multiple results, and except the first, all the remaining are wrong. You should solve this by adding a guard to the last clause:

separate([],[],[]).
separate([X|Y],[X|Z],S):-number(X),separate(Y,Z,S).
separate([X|Y],Z,[X|S]):-\+ number(X),separate(Y,Z,S).

Where \+ acts like a "not" in the sense that \+ number(X) will succeed if Prolog cannot match number(X).

A final note is that what you see is not really a memory address: it is simply an uninstantiated variable, although that is of course a minor remark.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Wasn't sure if it's a memory address or not, but it was the closest I thought it was, thanks for clearing that up too. The \+ is unknown to me and was never mentioned in our script. – Streamline Jan 21 '17 at 18:16
  • @Streamline: ah `\+` acts like a "not" (although it is dangerous to say that). It is a not in the sense that if Prolog fails to match `number(a)` for instance, `\+ number(a)` will succeed. – Willem Van Onsem Jan 21 '17 at 18:17