![]() |
![]() |
|
home—info—lectures—exams—archive
% 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). |
home—info—lectures—exams—archive
©2008, Ian Barland, Radford University Last modified 2008.Nov.26 (Wed) |
Please mail any suggestions (incl. typos, broken links) to ibarland ![]() |
![]() |