0

I am new to Prolog and I am trying to remove the last element from a list. The code I have tried:

removeLast([],[_]).
removeLast([_|T], [_|OT]):-removeLast(T, OT).

Obtained from here. I executed the code from SWi Prolog and I am getting a weird output ...

1 ?- 
|    removeLast(X, [1,2,3,4]).
X = [_G299, _G302, _G305] .

This is supposed to show [1,2,3], instead it is showing some numbers(?)

I don't know what am I doing wrong, why it is displaying in this format? I tried every Google combination I know of to search this term, although I saw people use this format directly in their queries like, parent(X, _G3248).

Update: Thanks to @lurker, modifying the code to the original format gives the output correctly:

removeLast([],[_]).
removeLast([X|T], [X|OT]):-removeLast(T, OT).

15 ?- removeLast(X, [1,2,3,4]).
X = [1, 2, 3] 

But can someone explain, what is _G3240?

Community
  • 1
  • 1
Gopikrishna S
  • 2,221
  • 4
  • 25
  • 39
  • What you wrote doesn't look like the code that's in the link you gave. Why are you using `_` in the second clause and do you know when it's appropriate to do so? There's a reason the solution in the link doesn't use it in the second clause. – lurker Apr 13 '14 at 02:04
  • Please correct me if am wrong. As I said, I am new to prolog. I understand that `_` is used for empty place holders? Like I don't want use an "unused-variable" there? – Gopikrishna S Apr 13 '14 at 02:08
  • Right. It's a "placeholder", sort of, and each `_` is different in this case. However, in the original solution, it uses `X` in both places. That's the same value in both places, and it matters very much. It's not unused. When a variable appears more than once in a clause, it's value is instantiated the same in all cases. That's why the original solution didn't use `_` in the second clause. You could do a `trace` to see what happens. – lurker Apr 13 '14 at 02:09
  • @lurker I modified the code, and got the output. Can you please explain what _is_ _G302? What is the name of it and when and where it is used? – Gopikrishna S Apr 13 '14 at 02:16
  • 1
    `_G302`, etc, is SWI Prolog's way of showing a variable which is a "don't care" but there may be several different ones. So they have different numbers on them. Your first attempt generated several "don't care" variables. Try this at the prompt: `X = [_,_,_].`. – lurker Apr 13 '14 at 02:16
  • Yeah, I got the junk, values. But what does this mean: `addup([3, 5, 7], _G322)`? Does this mean they are trying to store result in a "don't care" value? – Gopikrishna S Apr 13 '14 at 02:20
  • It means the second argument is an anonymous variable. Without knowing what `addup` does, I don't know if it's attempting to instantiate that variable or not. – lurker Apr 13 '14 at 02:26

1 Answers1

1

Here's the difference in the behavior of the solutions. Let's take the malfunctioning one.

removeLast([],[_]).

This rule says that if I have a list of one element, then the corresponding list with last element removed is [] and I don't care what that one element was (it could even be a variable). This is true, and a valid rule.

removeLast([_|T], [_|OT]) :- removeLast(T, OT).

This rule says that [_|T] is [_|OT] with the last element removed if I don't care what their first elements are and T is OT with its last element removed (following the same rules). This doesn't sound quite right. It means that if I am removing the last element from a list, I don't care what element I have in my result. So you get an arbitrary list of elements whose count is one less than your original list. But the elements don't match those at the front of the original list. In Prolog, the two _ instances are different anonymous variables. They are not unified.

The corrected clause is:

removeLast([X|T], [X|OT]) :- removeLast(T, OT).

This says that a list [X|T] is the list [X|OT] with its last element removed if T is the list OT with its last element removed. The common X means they share the same head of the list, which is correct. When the recursion reaches the very last element of the second argument, then the first clause is matched and that single-element tail is replaced by the empty list []. And then you get the correct, final result.

I refer to the _ variable as "anonymous" rather than "don't care" since there are some uses for anonymous variables in which their values do matter. Often though, as in this case, they are used when the value is not being used.

lurker
  • 56,987
  • 9
  • 69
  • 103
  • @GopikrishnaS no problem! I know the `_` can be a little confusing at first, especially when there is more than one of them around. – lurker Apr 13 '14 at 02:44