There is a so-called “comma list”, but its use is frowned upon as bad style; and a “regular” list is easier. Here’s an example (it works because the “,” operator is right-associative: (a,b,c) = ','(a,','(b,c)):
% don't do this
sum_comma_list((X,Xs), Sum) :- !, % this cut is needed
sum_comma_list(Xs, Sum0),
Sum is X + Sum0.
sum_comma_list(X, X). % X \= (_,_)
?- sum_list([1,2,3], Sum).
Sum = 6.
Here is better style (notice that it doesn’t need a cut and the clauses can be in any order and it also allows a 0-length list, whereas a “comma list” must have at least one item):
sum_list([X|Xs], Sum) :-
sum_list(Xs, Sum0),
Sum is X + Sum0.
sum_list([], 0).
?- sum_comma_list((1,2,3), Sum).
Sum = 6.
My favorite demonstration about the pitfalls of comma lists (as seen somewhere on the internets):
?- [A, B] = [A, B, C].
false. % of course
?- (A, B) = (A, B, C).
B = (B, C). % WAT?
Coming from a language that has “tuples” this second query should come as a nasty surprise. It also shows why comma lists are not tuples in the widely accepted meaning of the word “tuple”.
And of course [] (the empty list) is a thing while () (the empty tuple?) is not a thing, as you mention.
Both Python (hugely popular) and Haskell (hugely popular in some circles) have tuples that look like (a, b); and Prolog accepts this construct, and it seems to work. The end result is that you see a lot of Prolog code that uses those, some of it apparently coming from people teaching Prolog to other people, within the safe space of educational institutions.
Thank you, you are correct. However, no one who wants to use “tuples in Prolog” would start adding true as the last element of all their tuples, I thought. Maybe I am wrong.
Sometimes, when i have a goal/predicate as so pred(A, B) :- and i need to add an argument without adding causing pred/2 to become pred/3, I pass something like (X, Y) to bind with, say, B.
When placed before the original pred/2, these get found first.
Usually, its to try out things and to later rework the code without such contraption …
Yes, I use v(a, b, c) with the mnemonic “vector” or maybe “values”, if it is really so generic that I cannot come up with a short word that describes my a, b, c any better.
AFAIK, O’Keefe’s “The Craft of Prolog” already claims “never use a list for something of a fixed number of elements”. Instead, use a tuple as a compound term and try to give it a sensible name. For anonymous tuples with two arguments, use A-B which works nicely with library(pairs), keysort/2 and similar built-ins and libraries. I also tend to use v(…) if I see no need for a sensible name
The form A-B tends to be used with the implied semantics Key-Value, and that can lead to subtle bugs if you assume the Keys are unique (I just fixed some code that made such a mistake), even though keysort/2 explicitly makes no assumption about uniqueness of keys.
I’ve also seen A-B used for difference lists (and sometimes A\B), with the mental image of subtracting B from the end of A.
As others have said, best to use a tuple; v(A,B,C) is better than A-B-C (and also slightly more efficient), and even better if you can use something more meaningful than “v” for the functor name.
The “minus” as in A-B is only good for a pair, it doesn’t extend to A-B-C. That suffers the exact same problem as “comma lists”, BTW, just swapped:
?- A-B = A-B-C.
A = A-C,
B = C.
The “clean” way to extend - from a pair to a triple, quadriple etc would be to do the exact same thing you’d do with the comma:
There is a lot of interesting lessons to be learned from R. IIRC the c() in R is a function that combines or maybe concatenates its arguments to a one-dimensional vector (and it takes as many arguments as you give it…).
It seems that ECLiPSe has a very similar interface to arrays as R. In R at least you can at run time change the dimensions of an array (efficiently) by assigning a vector of dimensions to your array.