A small program that convinced me of the power of Prolog is a term rewrite rule system showing symbolic differentiation. Here is a variant of a program taken from Cloksin/Mellish.
% term rewrite rule system
% shows symbolic differentiation using term rewrite rules
:- op( 750 , xfx , ==> ) . % define rule operator ==>
:- op( 1180 , xfx , if ) . % define rule guard operator if
:- op( 250 , yfx , ´ ) . % define differentiation operator `
rw( Old , Old ) . % rule applyer
rw( Old , New ) :- subst( Old, Zw ) , ! , rw( Zw, New ).
subst( Old , New ) :- Old =.. [F,A|As] , % apply any substition to a subtree of Old to get New
substl( [F,A|As], Ns ) ,
New =.. Ns .
subst( Old , New ) :- ( Old ==> New if B ) , B . % inner substitutions first
substl( [A|As], [N|As] ) :- subst( A, N ) .
substl( [A|As], [A|Ns] ) :- substl( As, Ns ) .
0 * _ ==> 0 if true .
X + 0 ==> X if true .
1 * X ==> X if true .
X + X ==> 2 * X if true .
X ^ 1 ==> X if true .
A * X + B * X ==> (A+B) * X if integer(A) , integer(B) .
A * X + X ==> (1+A) * X if integer(A) .
X + B * X ==> (1+B) * X if integer(B) .
X - Y ==> Z if integer(X) , integer(Y) , Z is X - Y .
X - Y ==> X + -1 * Y if true .
X + Y ==> Z if integer(X) , integer(Y) , Z is X + Y .
W + X + Y ==> W + Z if integer(X) , integer(Y) , Z is X + Y .
X * Y ==> Z if integer(X) , integer(Y) , Z is X * Y .
X + Y ==> Y + X if integer(X) , not(integer(Y)) .
X + Y + Z ==> X + Z + Y if integer(Y) , not(integer(Z)) .
X * Y ==> Y * X if integer(Y) , not(integer(X)) .
X * Y * Z ==> X * Z * Y if integer(Z) , not(integer(Y)) .
X * (Y * Z) ==> X * Y * Z if true .
X * (1/X) ==> 1 if true .
-1 * (X+Y) ==> -1*X+ -1*Y if true .
A/(B/X) ==> A*X/B if true .
X ´ X ==> 1 if true .
C ´ _ ==> 0 if integer( C ) . % constants
(C*F) ´ X ==> C * F´X if integer( C ) .
C ´ X ==> 0 if atom( C ) , \+ C=X . % partial differentiation
(C*F) ´ X ==> C * F´X if atom( C ) , \+ C=X .
(X^N) ´ X ==> N * X^(N-1) if integer( N ) , \+ N=0 .
exp(X) ´ X ==> exp(X) if true .
ln(X) ´ X ==> 1 / X if true .
sin(X) ´ X ==> cos(X) if true .
cos(X) ´ X ==> -1 * sin(X) if true .
(F+G) ´ X ==> F´X + G´X if true . % sum rule
FG ´ X ==> FG´G * G´X if FG=..[_,G] , \+ G=X . % chaining rule
(F*G) ´ X ==> G*F´X + F*G´X if true . % product rule
(F/G) ´ X ==> (G*F´X - F*G´X) / G^2 if true . % quotient rule
FIX´X ==> 1 / FFIX ´ FIX if FIX=..[FI,X], inv(FI,F), FFIX=..[F,FIX] . % invers f rule
% FI means f^-1 , FIX means f^-1(X) , FFIX means f(f^-1(X)) , FFIX´FIX means f'(f^-1(X))
% invers rule, i.e. f^-1'(X) = 1 / f'(f^-1(X))
tan(X) ==> sin(X) / cos(X) if true .
inv(arcsin,sin). % f^-1=arcsin,f=sin
inv(arccos,cos).
inv(arctan,tan).
inv(arccot,cot).
test1(E) :- rw( (x^6)´x , E ) . % 1st derivative
test2(E) :- rw( (x^6)´x´x , E ) . % 2nd derivative
test3(E) :- rw( (c*x*y)´x´y , E ) . % derivative to x and to y
test4(E) :- rw( (sin(y*x))´x , E ) . % chaining rule
test5(E) :- rw( (arccos(x))´x , E ) . % derivative of invers funtion
Stepwise execution of the test queries on a console shows the computation of the derivative, e.g.:
?- test1(E).
E = x^6 ´ x ;
E = 6 * x^(6-1) ;
E = 6 * x^5 ;
false.
I like to use this program in my class because the part that computes the derivative is short and the incomplete simplification of formulas can easily be extended by the students as an exercise.