+–? arguments
When you write a Prolog predicate, it is useful to document with a comment that indicates how the arguments are intended to be used. The +–? convention lets you do this succinctly. In
% factorial(+N, -NFactorial)
the + in front of N indicates that N is intended to be an input to this predicate. If when such a predicate is called, the + argument is not given a value (instantiated) the predicate is likely to fail. Some predicates (e.g. <) have only + arguments, because they are ended to be used to test some condition and produce a true/false (i.e. true/fail) result.
The - in front of NFactorial indicates that NFactorial is intended to be an output from this predicate. Thus it is OK to provide an (uninstantiated) variable as the second argument when calling this predicate. If when such a predicate is called, the argument is given a value (instantiated), then the predicate is likely, in effect, to calculate the value for the the argument, and if this is not the same as the supplied value, the predicate will then fail.
Some predicates have "?" arguments that can be either inputs or outputs. Such predicates can be used in multiple ways - with all arguments instantiated, or with some instantiated. If not all are instantiated, then Prolog will try to find bindings for the variables given for the uninstantiated arguments. Here is a trivial but hopefully understandable example:
% twist(?Pair, ?TwistedPair)
% - invert the order of items in a 2-member list
twist([X, Y], [Y, X]).
?- twist(X, [a, b]).
X = [b, a]

?- twist([c, d], Y).
Y = [d, c]
Either the second argument can be instantiated, and twist calculates the appropriate value for the first argument, or else the first argument can be instantiated, and twist calculates the appropriate value for the second argument.
Another, perhaps unexpected, example occurs with the built-in predicate member:
?- member(X, [a, b]). % finds both possible bindings for X
X = a;
X = b.

?- member(a, X). % finds expressions for all sets containing "a" 
X = [a|_G312] ;
X = [_G311, a|_G315] ;
X = [_G311, _G314, a|_G318] ;
X = [_G311, _G314, _G317, a|_G321]   and so on for ever...
In the first solution to member(a, X), a is the first member of the solution. In the second solution, a is the second member, and so on. So member's header comment would include something like
% member(?Item, ?List)