diff options
Diffstat (limited to 'prolog/problems')
-rw-r--r-- | prolog/problems/lists/conc_3/en.py | 112 | ||||
-rw-r--r-- | prolog/problems/lists/conc_3/sl.py | 10 | ||||
-rw-r--r-- | prolog/problems/lists_advanced/rev_2/en.py | 4 |
3 files changed, 118 insertions, 8 deletions
diff --git a/prolog/problems/lists/conc_3/en.py b/prolog/problems/lists/conc_3/en.py index e25ae32..2e74e5e 100644 --- a/prolog/problems/lists/conc_3/en.py +++ b/prolog/problems/lists/conc_3/en.py @@ -10,4 +10,114 @@ description = '''\ X = [1,2,3]. </pre>''' -hint = {} +plan = ['''\ +<p><img src="[%@resource plan.svg%]" /></p> +''', '''\ +<p>Let's start with an easy question. What do I get if I concatenate an empty list and a list <code>L2</code>?</p> +''', '''\ +<p>Now, assume that the first list has exactly one element. Let's temporarily take it out which leaves us +with an empty list. But wait! Isn't this situation now similar to the one we dealt with before? Of course, we just +reduced the problem into a smaller one (by one element smaller). Let recursion solve this smaller problem. Just don't +forget to expand the recursion's result with the element you have taken out at the beginning...</p> +''', '''\ +<p>Declarative/logic reasoning: Assume the first list <code>L1</code> has head <code>H</code> and tail +<code>T</code>. If the recursive result of concatenating <code>T</code> and <code>L2</code> is some list +<code>L3</code>, and if we add element <code>H</code> at the beginning of list <code>L3</code>, what do we get? +A concatenation of <code>L1</code> and <code>L2</code>!</p> +'''] + +hint = { + 'eq_instead_of_equ': '''\ +<p>The operator <code>==</code> is "stricter" than operator <code>=</code> in the sense that +for the latter it is enough to be able to make the two operands equal (unification). Perhaps by using <code>=</code> +you can make the predicate <code>rev/2</code> more general (e.g. able to work with output arguments becoming inputs).</p> +<p>Of course, you can also solve the exercise without explicit use of either of these two operators, just +remember that unification is implicitly performed with the predicate's arguments (head of clause).</p> +''', + + 'eq_instead_of_equ_markup': '''\ +<p>Perhaps the operator for unification (=) would be better?</p> +''', + + 'base_case': '''\ +<p>Did you think of a base case? What is the simplest possible case? +What's the answer if, for example, the first list is empty? (Just the first list should be empty, +the second one can be arbitrary.)</p> +''', + + 'base_case_arbitrary': '''\ +<p>How can the result of concatenating two lists be an arbitrary list (a variable without an assigned value)?</p> +<p>If your base case is similar to <code>conc([], L, _)</code>, +then you should rethink it: what is the result of the concatenation, what do you return as the result? +The base case <em>always</em> fully specifies the result, usually there are no unknowns (<code>_</code> +or variables without assigned values) in what is being returned as the result.</p> +''', + + 'predicate_always_false': '''\ +<p>It seems your predicate is <emph>always</emph> "false". Did you give it the correct name, +or is it perhaps misspelled?</p> +<p>If the name is correct, check whether something else is misspelled, perhaps there is a full stop instead of +a comma or vice versa, or maybe you typed a variable name in lowercase?</p> +<p>It is, of course, also possible that your conditions are too restrictive, or even impossible to satisfy +(as would be, for example, the condition that an empty list <code>[]</code> is equal to a list with +exactly three elements <code>[A,B,C]</code>, +or something similarly impossible).</p> +''', + + 'timeout': '''\ +<p>Is there an infinite recursion at work here? How will it ever stop?</p> +<p>Or perhaps is there a missing, faulty, or simply incompatible (with the general recursive case) base case? +Are you maybe reducing the first list, but your base case stops with an empty second list (or vice versa)?</p> +''', + + 'second_list_iteration': '''\ +<p>It seems you're processing (reducing) the second list. The mechanism at work is correct, however, +the final ordering of the elements is not. It's better to process the first list in this way and +leave the second one as is.</p> +<p>There's another reason to process the first list: in this way the solution of this essential exercise +will be the same for everyone, and we'll be able to use <code>conc/3</code> in a standardised way. This +will be very important later on.</p> +''', + + 'insertion_into_second_list': ''' +<p>Is your recursive call of the form <code>conc(T, [H|L2], ...)</code>? +Don't insert the first list's head into the second list as this will result in the wrong ordering +of the elements. Let the recursion alone take care of concatenating the first list's tail +<code>T</code> with the second list <code>L2</code>, and then, when returning the complete result, +add the first list's head <code>H</code> into its proper place.</p> +''', + + 'two_heads': '''\ +<p>Do you really need two list heads? Are you trying to reduce both lists? This is not a good idea, it is +difficult to solve the exercise in this way. Rather simply reduce the first list only, and leave the +other list as is.</p> +''', + + 'two_heads_markup': '''\ +<p>Do you really need two list heads?</p> +''', + + 'forcing_result_onto_recursion': ''' +<p>Don't force the result onto recursion, don't tell it what it should return. Just assume it will do its job. +If this assumption is correct, then the rule will work for a larger case.</p> +<p>Is your recursive call of the form <code>conc(T, L2, [H|...])</code>? This forces the recursive call to +<em>return</em> the head at the start of the concatenated list. But it doesn't know of this head, because you just +took it away! Inserting the head into the result, returned by the recursive call, is your job. To put it shortly, +insert <code>H</code> outside of the recursive call.</p> +''', + + 'final_hint': '''\ +<p>Predicate <code>conc/3</code> will be useful for much more than just concatenating two lists. +Among other things it can be used "in the other direction" -- for dividing a list into two parts. Try the +following queries:</p> +<p><code>?- conc(L1, L2, [a,b,c,d]).</code></p> +<p><code>?- conc([X,Y], L2, [a,b,c,d,e,f]).</code></p> +<p>Did you notice that the second query returned the first two elements from the list <code>[a,b,c,d,e,f]</code>?</p> +<p>Furthermore, <code>conc/3</code> is useful to search for patterns in a list, e.g.:</p> +<p><code>?- conc(_, [X,X|_], [a,b,c,c,d,e,f,f,g,h,h]).</code></p> +<p>Right, this query finds all possibilities where two identical elements appear one after the other in a list +(pattern X,X). Basically the query said that "there are some elements (possibly zero) in front, then follow two +identical elements, and then again some elements (possibly zero) at the end."</p> +<p>There are many other usages of <code>conc/3</code>, you will discover them along the way.</p> +''', +} diff --git a/prolog/problems/lists/conc_3/sl.py b/prolog/problems/lists/conc_3/sl.py index be2590e..5b0a639 100644 --- a/prolog/problems/lists/conc_3/sl.py +++ b/prolog/problems/lists/conc_3/sl.py @@ -92,8 +92,8 @@ res težko prišel do pravilne rešitve. Raje zmanjšuj samo prvi seznam in pust 'forcing_result_onto_recursion': ''' <p>Ne vsiljuj rekurziji kaj naj vrne, prepusti se ji. To je tisti del, ko narediš predpostavko, če je ta izpolnjena, potem bo tvoje pravilo delovalo za večji primer.</p> -<p>Je tvoj rekurzivni klic oblike <code>conc(T, L2 [H|...])</code>? S tem vsiljuješ rekurziji -da mora <emph>vrniti</emph> tudi glavo, ki si jo prej že dal začasno stran. Glavo moraš na koncu na primerno mesto +<p>Je tvoj rekurzivni klic oblike <code>conc(T, L2, [H|...])</code>? S tem vsiljuješ rekurziji +da mora <em>vrniti</em> tudi glavo, ki si jo prej že dal začasno stran. Glavo moraš na koncu na primerno mesto vstaviti ti. Skratka, glavo <code>H</code> dodaj izven rekurzivnega klica.</p> ''', @@ -105,9 +105,9 @@ Med drugim je uporaben "v obratni smeri" za delitev seznama na dva dela, poskusi <p>Si opazil, da je drugo vprašanje v bistvu vrnilo prva dva elementa iz seznama <code>[a,b,c,d,e,f]</code>?</p> <p>Nadalje je <code>conc/3</code> uporaben za iskanje vzorcev v seznamu, npr. takole:</p> <p><code>?- conc(_, [X,X|_], [a,b,c,c,d,e,f,f,g,h,h]).</code></p> -<p>Tako je, to vprašanje najde vse možnosti, kjer se dva elementa ponovita drug za drugim v seznamu (vzorec X,X). +<p>Tako je, to vprašanje najde vse možnosti, kjer se dva enaka elementa ponovita drug za drugim v seznamu (vzorec X,X). V bistvu smo rekli "nekaj poljubnih elementov (lahko tudi nič) je spredaj, potem sta dva enaka, potem pa spet nekaj -poljubnih elementov (lahko nič) zadaj." -Še veliko drugih koristi bo od <code>conc/3</code>, jih boš že še sproti spoznal.</p> +poljubnih elementov (lahko nič) zadaj."</p> +<p>Še veliko drugih koristi bo od <code>conc/3</code>, jih boš že še sproti spoznal.</p> ''', } diff --git a/prolog/problems/lists_advanced/rev_2/en.py b/prolog/problems/lists_advanced/rev_2/en.py index 3b85a74..dbb08a2 100644 --- a/prolog/problems/lists_advanced/rev_2/en.py +++ b/prolog/problems/lists_advanced/rev_2/en.py @@ -25,7 +25,7 @@ and if I assume the recursion reverses tail <code>T</code> into reversed tail <c hint = { 'eq_instead_of_equ': '''\ <p>The operator <code>==</code> is "stricter" than operator <code>=</code> in the sense that -for the latter it is enough to be able to make two elements equal (unification). Perhaps by using <code>=</code> +for the latter it is enough to be able to make the two operands equal (unification). Perhaps by using <code>=</code> you can make the predicate <code>rev/2</code> more general (e.g. able to work with output arguments becoming inputs).</p> <p>Of course, you can also solve the exercise without explicit use of either of these two operators, just remember that unification is implicitly performed with the predicate's arguments (head of clause).</p> @@ -72,7 +72,7 @@ an assigned value)!</p> <p>Don't force the result onto recursion, don't tell it what it should return. Just assume it will do its job. If this assumption is correct, then the rule will work for a larger case.</p> <p>Is your recursive call of the form <code>rev(T, [RevTail|H])</code>? This forces the recursive call to -<emph>return</emph> the head at the end of the list. But it doesn't know of this head, because you just +<em>return</em> the head at the end of the list. But it doesn't know of this head, because you just took it away! Inserting the head into the result, returned by the recursive call, is your job. To put it shortly, insert <code>H</code> outside of the recursive call.</p> ''', |