Use arithmetic operators as tuple constructors and cons pairs
If you need to pass a single structure consisting of two or more values, the most obvious thing to use is a list, e.g. [A,B]
. That's really verbose, though.
There's an alternative. Prolog values can store a pretty much arbitrary nested structure, which isn't evaluated. Here's an example showing how that works:
| ?- member(member(A,B),C).
C = [member(A,B)|_] ? ;
C = [_,member(A,B)|_] ? ;
(etc.)
member(A,B)
is just a named tuple in this situation, and the outside member
(which is a function call) is treating it as such.
Although named tuples are fairly useful in non-golfed Prolog programming, they might seem even more verbose than the list approach. However, we can use pretty much arbitrary characters in the name of the tuple constructor (assuming they're properly quoted); instead of something cute like member
or a single character like a
, we can do something like this:
| ?- A = '-'('/'(1,2), '/'(3,4)).
A = 1/2-3/4
Here, our tuple constructors are '-'
and '/'
. And it's interesting to note what the pretty-printer did with them; it's using infix notation for the tuples. This is really terse, and parses the same way that the comparable arithmetic operation would. (This also explains why arithmetic uses is
not =
; A = 1+2
would unify A
with the tuple '+'(1,2)
, so separate syntax is needed to actually evaluate the unevaluated arithmetic expression.) Because a tuple constructor has to be called something, you may as well use a character that has a terse syntax (and as a bonus, -
and /
are some of the most common choices in non-golfed code too when they want a quick throwaway tuple constructor rather than something meaningful, in much the same way that i
is often used as a loop variable, so they're entirely reasonable to use in your input and output if you happen to want a tuple there for some reason).
'-'
and '/'
are good choices for tuple constructors because they have well-behaved and useful precedence, allowing you to write tuple literals tersely. However, note that you don't need to worry about precedence when intermediate values are produced inside the program. Prolog keeps the tuples stored as a tree rather than as source code, and pretty-printers can output it unambiguously:
| ?- A = '-'('-'(1,2), '-'(3,4)).
A = 1-2-(3-4)
Because the tuple syntax is so terse (f(A,B)
is no shorter than f(A-B)
), you can replace multiple prediccate arguments with tuples at no cost, meaning that if a predicate needs to pass two or more of its arguments to another predicate, you can often form them into a tuple and just pass the tuple (although this will require changing all calls to the predicate, in addition to the predicate itself, to use an appropriate mix of tuple constructors and commas).
Another advantage of this syntax is if you need to use lists internally (rather than to interoperate with standard predicates); a list is basically just a set of nested cons cells, and a cons cell is just a tuple with constructor '.'
, as can be seen here:
| ?- Q = '.'('.'(A,B),'.'(C,D)).
Q = [[A|B],C|D]
If your code uses lists "manually", it can make a lot of sense to use a less bulky tuple constructor than '.'
. A common choice for me is to represent a cons cell as '/'(Tail,Head)
(because it's about the most readable you can get in debug output without wasting characters). Note that you'll probably want your own []
equivalent too; you could use []
but it's two bytes long, and there are plenty of one-byte atoms (all the lowercase letters) that you can use instead.
So for example, the following list:
[1,2,3]
could be converted into a manual representation in the same number of characters like this:
x/3/2/1
whilst gaining the advantage that [H|T]
-style pattern matches can now be written more tersely as T/H
, and a test against the empty list as just x
rather than the longer []
. (Of course, this comes with the obvious disadvantage that member
, append
, etc., won't work on this representation.)