![]() |
![]() |
|
home—info—lectures—exams—hws—archive
- Review N2.ss soln: - First we add ifNeg; eval and toString are straight copies; note the trick used in parsing if0 and ifNegs: ((if ... make-is0-expr make-ifNeg-expr) e1 e2 e3) for parse we do a bit of thinking. - [q: should I have included a 'parse-expect!'?] - mod straightforward, though I tweaked the test-case. (Too bad check-within can only be used at top-level.) - Note how id's are represented by strings, but for abstraction we define id?, id=? - subst: follows the data def'n - Note that for checking subst: it's annoying check-expect must be at top-level. I used an editor/macro, to help make test cases based on eval test cases. Finish up prolog (really!)
1 %%%%%%%%%%%%%% 2 % Sorting: 3 % We'll just provide the 'spec': 4 % L2 is a sorted version of L1 if: 5 % - L1 is a permutation (re-arrangement) of L2, and 6 % - L2 is in ascending order (er, non-decreasing). 7 8 scrapSort(L1,L2) :- permutation(L1,L2), nondecreasing(L2). 9 10 % Here're the helper functions: 11 12 nondecreasing([]). 13 nondecreasing([_]). 14 nondecreasing([F,S|R]) :- F=<S, nondecreasing([S|R]). 15 16 17 badPerm1([],[]). 18 badPerm1([F|R],Y) :- append2(Y1,[F|Y2],Y), 19 append2(Y1,Y2,PY), 20 badPerm1(R,PY). 21 % This is a correct *specification* of permutation. 22 % However, it has several drawbacks: 23 % (a) written non-intuitively, 24 % (b) using 'append' is a sledgehammer (poor performance too), 25 % (c) it only half-works, in Prolog: 26 % badPerm1([3,4,5],[5,3,4]) is true 27 % but 28 % badPerm1([3,4,5],X) gives only *one* answer 29 % and then loops forever. 30 % However, it works 'in reverse': 31 % badPerm1(X,[3,4,5]) gives all solutions. 32 33 badPerm2([],[]). 34 badPerm2([F|R],Y) :- remove(F,Y,Z), badPerm2(Z,R). 35 % 36 % This is also a correct spec, 37 % and it fixes drawbacks (a) and (b), 38 % but still suffers from (c). 39 % In fact, it's worse: badPerm2 no longer 40 % works in reverse -- badPerm2(X,[3,4,5]) gives 41 % *two* (?!) solutions, and then backtracks 42 % into la-la land. 43 44 % Here's a fully-working version: 45 % like badPerm2 except that it destructures the *return* value. 46 % 47 permutation([],[]). 48 permutation(X,[F|R]) :- remove(F,X,Z), permutation(Z,R). 49 50 remove(F,[F|L1],L1). 51 remove(F,[G|L1],[G|L2]) :- remove(F,L1,L2). 52 53 54 55 %% Now, back to sorting... 56 % Reflecting on scrapSort: 57 % Consider the *order* of solutions 58 % permutation([3,4,5],X) and permutation([5,4,3],X). 59 % How many permutations does scrapSort([3,4,5],X) look at? 60 % How about scrapSort ([5,4,3],X) look at? 61 % 62 % Now, consider this problem amplified: 63 % scrapSort([8,7,6,5,4,3,2,1],X) runs okay. But 64 % But scrapSort([10,9,8,7,6,5,4,3,2,1],X) takes a while. 65 % 66 % The name "scrapSort" was chosen because its performance 67 % is a piece of scrap: O(n!). 68 69 70 71 72 73 74 75 % Ironically, 'quicksort' is more straightforward than 'scrapsort', 76 % even though we specify *how* to sort rather than *what sorted means*. 77 % 78 79 80 % QuickSort 81 % Author: Varesano Fabio 82 % http://www.varesano.net/blog/fabio/quick+sort+implemented+prolog 83 84 /* [+,-] */ 85 quicksort([], []). 86 quicksort([HEAD | TAIL], SORTED) :- partition(HEAD, TAIL, LEFT, RIGHT), 87 quicksort(LEFT, SORTEDL), 88 quicksort(RIGHT, SORTEDR), 89 append(SORTEDL, [HEAD | SORTEDR], SORTED). 90 91 /* [+,+,-,-] */ 92 partition(PIVOT, [], [], []). 93 partition(PIVOT, [HEAD | TAIL], [HEAD | LEFT], RIGHT) :- HEAD @=< PIVOT, 94 partition(PIVOT, TAIL, LEFT, RIGHT). 95 partition(PIVOT, [HEAD | TAIL], LEFT, [HEAD | RIGHT]) :- HEAD @> PIVOT, 96 partition(PIVOT, TAIL, LEFT, RIGHT). 97 98 /* [+,+,-] */ 99 append([], LIST, LIST). 100 append([HEAD | LIST1], LIST2, [HEAD | LIST3]) :- append(LIST1, LIST2, LIST3). 101 102 103 104 105 106 107 108 % Here is a another, more verbose version 109 % (the version I started writing myself ... 110 % Note that I'm used to partitioning into three sections, 111 % so that we always *reduce* the size of a partition 112 % (even if our pivot is the maximum value). 113 % Study the above sol'n, to see how the Prolog 114 % makes sure we always recur on smaller lists (even 115 % when the pivot is the maximum value *and* when 116 % it's the minimum value). 117 118 qsort([],[]). 119 qsort([F|R],L2) :- partition([F|R],F,Sm,Eq,Lr), 120 qsort(Sm,SmSorted), 121 qsort(Lr,LrSorted), 122 append3(SmSorted,Eq,LrSorted,L2). 123 124 partition([],_,[],[],[]). 125 partition([F|R],Pivot,Smaller,Equal,Larger) :- 126 F<Pivot, 127 Smaller = [F|SmallerRest], 128 partition(R,Pivot,SmallerRest,Equal,Larger). 129 partition([F|R],Pivot,Smaller,Equal,Larger) :- 130 F=Pivot, 131 Equal = [F|EqualRest], 132 partition(R,Pivot,Smaller,EqualRest,Larger). 133 partition([F|R],Pivot,Smaller,Equal,Larger) :- 134 F>Pivot, 135 Larger = [F|LargerRest], 136 partition(R,Pivot,Smaller,Equal,LargerRest). 137 138 139 append3(L1,L2,L3,All) :- append2(L1,L2,L1and2), append2(L1and2,L3,All). 140 append2([],L2,L2). 141 append2([F|R],L2,[F|AllRest]) :- append2(R,L2,AllRest). 142 143 144 145 146 /***************** 147 Reflections/thoughts on prolog: 148 * The idea of declarative programming is cool: 149 Just by specifying what *constitutes* a correct answer, 150 you can write a program (and often it's efficient). 151 + Sometimes though, it's too inefficient (scrapSort). 152 + Worse though: to really write Prolog, you need to 153 thoroughly understand *how* it implements searching 154 (badPerm). 155 156 + Seeing how different 'cultures' compute is mind-expanding; 157 * Pattern matching: Way cool! 158 This is something *any* language can use 159 (ML, Haskell; Scheme has a 'match' library: 160 http://www.radford.edu/itec380/2009fall-ibarland/Lectures/matching.ss 161 162 * The idea of specifying correctness of an answer 163 (separately from an algorithm) 164 makes me a better [Java, whatever] programmer: 165 often having a clean spec of correctness 166 leads directly to clean, correct code. 167 *****************/ |
home—info—lectures—exams—hws—archive
©2009, Ian Barland, Radford University Last modified 2009.Nov.18 (Wed) |
Please mail any suggestions (incl. typos, broken links) to ibarland ![]() |
![]() |