RU beehive logo ITEC dept promo banner
ITEC 380
2008fall
ibarland

homeinfolecturesexamsarchive

lect12a
Prolog examples

We spend the week working through the following examples:
     % A note on numbers:
     %
     coolerThan(X,Y) :- X > Y.
     %
     % prolog has no problem with coolerThan(4,7).
     % But what about coolerThan(4,X) --
     % What do you expect the answer should be?
     
     % How about:
      
     f(X,Y) :- Y is X*X*X*X*X - 101*X*X*X*X - 10*X*X*X + 1010*X*X + 9*X - 909.
     
     % What if we query f(X,0) -- this means
     % prolog has to be smart enough to handle 5th-degree polynomials.
     % While you can imagine prolog designers lookup up the quartic formula
     % and supporting it in the language,
     % it turns out there is *no* closed-form solution for degree 5 and higher (!!)
     %  [This is a surprising result of math -- Galois.]
     % NB I happened to construct f so that it has nice roots though:
     %    f = (x-1)(x+1)(x-3)(x+3)(x-101)
     
     
     
     % Define factorial in Prolog:
     %   (define (! n)
     %      (if (zero? n)
     %          1
     %          (* n (! (sub1 n)))))
     %
     % Here's what we want to say:
     %
     %   fact(0,1).
     %   fact(N,NF) := NF = N*Z, fact(N-1,Z).
     
     % However, it gives an error! -- 
     % prolog sees "NF = N*Z",
     % and it's expecting too much to try to find *all* values of NF,Z
     % which would make this true.
     % Even writing "NF is N*Z" doesn't help, since Z isn't instantiated.
     % Instead, we'll have alter our spec, so that Z gets 
     % instantiated before we mention N*Z.
     
     fact(N,NF) :- Nless1 is N-1,
                   fact(Nless1,Z), 
                   NF is N*Z.
     fact(0,1).
     
     
     % Let's try it.
     % Uh-oh, infinite loop!  Why?
     % Solution: swap the order.
     %
     % Now it seems better.
     % But what does fact(3,7) do?  What about fact(3,N), if we reject 6?
     %
     % Solution: add "N>1" to the recursive case.
     % Why does it fix Q2?
     %
     % We see that (esp with numbers), prolog isn't as purely declarative
     % as we'd like.  Instead, we're forced to think about how it implements
     % its matching engine :-(  Arguably, that's a shortcoming of Prolog.
     % (Note that Mathematica goes to great lengths to handle numbers,
     %  although it's more functional than declarative.
     %
     %
     
     % Write: len (length of a list) (remind yourself of scheme version):
     len([],0).
     len([_|R],X) :- len(R,Y), X is Y+1.
     
     % A version of 'reverse' which requires 'removeLast' and 'last':
     reverse([],[]).
     reverse([F|R],L2) :- last(L2,F), removeLast(L2,L2less), reverse(R,L2less).
     
     %  removeLast, Last -- not included in notes, 
     %  since it's part of hw05  !!
     
     
     
     %% Alternate version: An accumulator variable:
     reverse(L1,L2) :- reverseHelp( L1, [], L2 ).
     
     reverseHelp([],Acc,Acc).
     reverseHelp([F|R],Acc,Out) :- reverseHelp(R,[F|Acc],Out).
     
     
     filterSmallerThan(Threshold,[],[]).
     filterSmallerThan(Threshold,[F|R],SmallerRest) :- 
           F >= Threshold, 
           filterSmallerThan(Threshold,R,SmallerRest).
     filterSmallerThan(Threshold,[F|R],[F|SmallerRest]) :- 
           F < Threshold, 
           filterSmallerThan(Threshold,R,SmallerRest).
     
     
     %%%%%%%%%%%%%%
     % Sorting:
     % We'll just provide the 'spec':
     % L2 is a sorted version of L1 if:
     %  - L1 and L2 have the same elements, and
     %  - L2 is in ascending order (er, non-decreasing).
     
     scrapSort(L1,L2) :- equalSets(L1,L2), nondecreasing(L2).
     %
     % It's name "scrapSort", because it actually runs like,
     % um, (something we should) scrap.
     %  - from this spec, Prolog would search all solutions,
     %    which could be O(n!), for a list of length n.
     %  - even worse(!?): without care, we can't use L2
     %    as an output parameter at all -- we'll recur
     %    infinitely when backtracking through 'subset'.
     %    There *is* a solution using Prolog's "cut" operator,
     %    but that's beyond the basic-prolog we aim to cover
     %    in this course.
      
     % Here're the helper functions:
     
     nondecreasing([]).
     nondecreasing([_]).
     nondecreasing([F|[S|R]]) :- F=<S, nondecreasing([S|R]).
     
     equalSets(L1,L2) :- subset(L1,L2), subset(L2,L1).
     
     mem(X,[X|_]).
     mem(X,[_|R]) :- mem(X,R).
     
     
     subset([],X) :- is_list(X).
     subset([F|R],X) :- mem(F,X), remove(F,X,Z), subset(R,Z).
     
     remove(F,[F|L1],L1).
     remove(F,[G|L1],[G|L2]) :- remove(F,L1,L2).
     
     
     
     
     
     % Ironically, 'quicksort' is more straightforward than 'scrapsort',
     % even though we specify *how* to sort rather than *what sorted means*.
     %
     
     
     %  QuickSort
     %  Author: Varesano Fabio
     %  http://www.varesano.net/blog/fabio/quick+sort+implemented+prolog
     
     /* [+,-] */
     quicksort([], []).
     quicksort([HEAD | TAIL], SORTED) :- partition(HEAD, TAIL, LEFT, RIGHT),
                                         quicksort(LEFT, SORTEDL),
                                         quicksort(RIGHT, SORTEDR),
                                         append(SORTEDL, [HEAD | SORTEDR], SORTED).
     
     /* [+,+,-,-] */
     partition(PIVOT, [], [], []).
     partition(PIVOT, [HEAD | TAIL], [HEAD | LEFT], RIGHT) :- HEAD @=< PIVOT,
                                                              partition(PIVOT, TAIL, LEFT, RIGHT).
     partition(PIVOT, [HEAD | TAIL], LEFT, [HEAD | RIGHT]) :- HEAD @> PIVOT,
                                                              partition(PIVOT, TAIL, LEFT, RIGHT).
     
     /* [+,+,-] */
     append([], LIST, LIST).
     append([HEAD | LIST1], LIST2, [HEAD | LIST3]) :- append(LIST1, LIST2, LIST3).
     
     
     
     
     
     
     
     % Here is a another, more verbose version
     % (the version I started writing myself ... 
     % Note that I'm used to partitioning into three sections,
     % so that we always *reduce* the size of a partition
     % (even if our pivot is the maximum value).
     % Study the above sol'n, to see how the Prolog
     % makes sure we always recur on smaller lists (even
     % when the pivot is the maximum value).
     
     qsort([],[]).
     qsort([F|R],L2) :- partition([F|R],F,Sm,Eq,Lr), 
                        qsort(Sm,SmSorted), 
     		   qsort(Lr,LrSorted), 
     	           append3(SmSorted,Eq,LrSorted,L2).
     
     partition([],_,[],[],[]).
     partition([F|R],Pivot,[F|SmallerRest],Equal,Larger) :- 
       F<Pivot,
       partition(R,Pivot,SmallerRest,Equal,Larger).
     partition([F|R],Pivot,Smaller,[F|EqualRest],Larger) :- 
       F=Pivot, 
       partition(R,Pivot,Smaller,EqualRest,Larger).
     partition([F|R],Pivot,Smaller,Equal,[F|LargerRest]) :- 
       F>Pivot, 
       partition(R,Pivot,Smaller,Equal,LargerRest).
     
     
     append3(L1,L2,L3,All) :- append2(L1,L2,L1and2), append2(L1and2,L3,All).
     append2([],L2,L2).
     append2([F|R],L2,[F|AllRest]) :- append2(R,L2,AllRest).
     
     
     

homeinfolecturesexamsarchive


©2008, Ian Barland, Radford University
Last modified 2008.Nov.26 (Wed)
Please mail any suggestions
(incl. typos, broken links)
to iba�rlandrad�ford.edu
Powered by PLT Scheme