I'm learning Prolog and I followed this tutorial for graphs. Here's my code:
path(X, Y, Length, [X,Y], _) :-
connect(X, Y, Length).
path(X, Y, Length, [X|P], V) :-
\+ member(X, V),
connect(X, Z, Length1),
path(Z, Y, Length2, P, [X|V]),
Length is Length1 + Length2.
To use this, I call
?- path(a, f, Length, Path, []).
However, I would like to shorten it to:
?- path(a, f, Length, Path).
But I can't get the default parameters to work.
Quite straight-forward: just define a predicate with the same name that calls the predicate doing the work:
path(X, Y, Length, Path) :-
path(X, Y, Length, Path, []).
In Prolog, predicates are always referred to with Name/Arity
because same name but different arity makes them two separate predicates. So, now your program will have both path/4
and path/5
defined.
As to naming: if both predicates are part of your interface, they should have the same name. Many examples in Prolog standard libraries, for example format/1
, format/2
, format/3
.
If, however, the working predicate is only meant to be used as a helper predicate, usually you give it a suffix. To use something simple as list_max/2
:
list_max([X|Xs], Max) :-
list_max_SUFFIX(Xs, X, Max).
I have seen code where SUFFIX
is just an underscore: list_max_/3
(and you keep adding underscores for more helper predicates down the same predicate lineage); or, underscore + number: list_max_1/3
(and you increment the number); or, _aux
+ optional number, if you have more: list_max_aux/3
. Using the underscore + number:
list_max_1([], Max, Max).
list_max_1([X|Xs], Max0, Max) :-
compare(Order, X, Max0),
list_max_2(Order, X, Max0, Xs, Max).
list_max_2(<, _, Max0, Xs, Max) :- list_max_1(Xs, Max0, Max).
list_max_2(=, _, Max0, Xs, Max) :- list_max_1(Xs, Max0, Max).
list_max_2(>, X, _, Xs, Max) :- list_max_1(Xs, X, Max).
But wait, there's more. If you use a naming scheme for your predicates where the name represents the arguments, you get for example setup_call_cleanup/3
, and call_cleanup/2
, defined as setup_call_cleanup(true, Goal, Cleanup)
. With this naming scheme, you would call your "path" predicates maybe from_to_length_path/4
and from_to_length_path_acc/5
. I find this naming scheme nice because it is self-documenting, but as this example shows, it could become excessive if your predicate has too many arguments.