/* SIMPLIFY. The aim of the predicate simplify is to reshuffle expressions which are sums of unknowns (represented by Prolog atoms) and integers so that all the unknowns are at the start and the sum of all the integers is at the end, e.g. x+3+y+4+z gets reshuffled to x+y+z+7 This is (a) useful in mathematical manipulations by computer and (b) an illustration of a useful technique called "difference pairs". To summarise the idea: a structure such as +(a,+(b,c)) could be drawn as + / \ a + / \ b c The idea is that when constructing such things you can represent intermediate stages as the "difference" of + / \ a + / \ b Zend and the variable Zend. To move to the next stage, you just have to instantiate Zend as something; if the next stage is also intermediate, why not another "difference pair", e.g. Zend = + / \ c Zend2 with Zend2 uninstantiated, and so on. The predicate normalise defined below shows the idea in practice: in normalise(Formula,V,Vend,N,Nend) the unknowns (Prolog atoms) are collected in the difference pair of V and Vend, and the integers are collected in the difference pair of N and Nend. The predicate simplify tidies up the final answer by instantiating the variable end of the structure in which the unknowns are collected to the structure in which the integers were collected. Note that in the body of simplify, the last argument of the call of normalise is 0 - this instantiates the variable at the trailing end of the integer-collecting structure, so that the goal Vend is N succeeds and evaluates the structure as the sum of all the integers! */ simplify(Formula,V) :- normalise(Formula,V,Vend,N,0), Vend is N. normalise(A+B,V,Vend,N,Nend) :- !, normalise(A,V,Vsofar,N,Nsofar), normalise(B,Vsofar,Vend,Nsofar,Nend). normalise(Atom,Atom+Vend,Vend,N,N) :- atom(Atom), !. normalise(Integer,V,V,Integer+N,N) :- integer(Integer).