summaryrefslogtreecommitdiff
path: root/prolog/problems/lists/conc_3/en.py
diff options
context:
space:
mode:
Diffstat (limited to 'prolog/problems/lists/conc_3/en.py')
-rw-r--r--prolog/problems/lists/conc_3/en.py112
1 files changed, 111 insertions, 1 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>
+''',
+}