Prolog is supposedly a declarative language - that is, one which specifies relationships between concepts using facts and rules and then uses a logic engine to answer queries that relate to those facts and rules, typically by finding bindings for variables that allow queries to succeed.

However, in "real" Prolog, there are built-in predicates that do no comform to this pattern. These include input-output "predicates" like see, seeing, seen, tell, telling, told, write, nl, prin, print, put, and read, get, get_byte, flush_output. All of these predicates succeed or fail independent of any logical aspect of the problem being solved - normally, in fact, they will succeed unless there is an error relating to the external input/output system - e.g. it may not be possible to read from a file because the user does not have permission to access the file, or because the file does not exist.

Even more extra-logical are assert, asserta, assertz and retract, retractall, which even change the program that is running.

Side-effects take Prolog programs out of the world of strict logic (as does the cut, which changes the way the inference engine operates in solving a query). Programs with side-effects are harder to analyse that programs without side-effects. The practical impact of side-effects on the understandabilty of Prolog programs depends on how they are used. For example, using memoisation to record facts inferred in order to save re-calculation is probably harmless, but using assert to create new rules might in some cases make debugging a program next to impossible. Use side-effects with care.