<p>This question is a very good example of a <em>bad</em> question for a forum like Stackoverflow. I am writing an answer because I feel you might use some advice, which, again, is very subjective. I wouldn't be surprised if the question gets closed as "opinion based". But first, an opinion on the exercises and the solutions:</p>

<h2>Second element of list</h2>

<p>Definitely, <code>second(X, [_,X|_]).</code> is to be preferred. It just looks more familiar. But you should be using the standard library anyway: <code>nth1(2, List, Element)</code>.</p>

<h2>Mirroring a binary tree</h2>

<p>The tree representation that the textbook suggests is a bit... unorthodox? A binary tree is almost invariably represented as a nested term, using two functors, for example:</p>

<ol>
<li><code>t/3</code> which is a non-empty tree, with <code>t(Value_at_node, Left_subtree, Right_subtree)</code></li>
<li><code>nil/0</code> which is an empty tree</li>
</ol>

<p>Here are some binary trees:</p>

<ul>
<li>The empty tree: <code>nil</code></li>
<li>A binary search tree holding {1,2,3}: <code>t(2, t(1, nil, nil), t(3, nil, nil))</code></li>
<li>A degenerate left-leaning binary tree holding the list [1,2,3] (if you traversed it pre-order): <code>t(1, t(2, t(3, nil, nil), nil), nil)</code></li>
</ul>

<p>So, to "mirror" a tree, you would write:</p>

<pre><code>mirror(nil, nil).
mirror(t(X, L, R), t(X, MR, ML)) :-
    mirror(L, ML),
    mirror(R, MR).
</code></pre>

<blockquote>
  <p>The empty tree, mirrored, is the empty tree.
  A non-empty tree, mirrored, has its left and right sub-trees swapped, and mirrored.</p>
</blockquote>

<p>That's all. No need for swapping, really, or anything else. It is also efficient: for any argument, only one of the two clauses will be evaluated because the first arguments are different functors, <code>nil/0</code> and <code>t/3</code> (Look-up "first argument indexing" for more information on this). If you would have instead written:</p>

<pre><code>mirror_x(T, MT) :-
    (   T = nil
    -&gt;  MT = nil
    ;   T = t(X, L, R),
        MT = t(X, MR, ML),
        mirror_x(L, ML),
        mirror_x(R, MR)
    ).
</code></pre>

<p>Than not only is this less readable (well...) but probably less efficient, too.</p>

<h2>On readability and efficiency</h2>

<p>Code is read by people and evaluated by machines. If you want to write readable code, you still might want to address it to other programmers and not to the machines that are going to evaluate it. Prolog implementations have gotten better and better at being efficient at evaluating code that is also more readable to people who have read and written a lot of Prolog code (do you recognize the feedback loop?). You might want to take a look at <a href="http://arxiv.org/pdf/0911.2899.pdf" rel="nofollow">Coding Guidelines for Prolog</a> if you are really interested in readability.</p>

<p>A first step towards getting used to Prolog is trying to solve the <a href="http://www.ic.unicamp.br/~meidanis/courses/mc336/2009s2/prolog/problemas/" rel="nofollow">99 Prolog Problems</a> (there are other sites with the same content). Follow the suggestion to avoid using built-ins. Then, look at the solutions and study them. Then, study the documentation of a Prolog implementation to see how much of these problems have been solved with built-in predicates or standard libraries. Then, study the implementations. You might find some real gems there: one of my favorite examples is the library definition of <a href="http://eu.swi-prolog.org/pldoc/doc/home/swipl/lib/swipl/library/lists.pl?show=src#nth0/3" rel="nofollow"><code>nth0/3</code></a>. Just look at this beauty ;-).</p>

<p>There is also a whole book written on the subject of good Prolog code: "The Craft of Prolog" by Richard O'Keefe. The efficiency measurements are quite outdated though. Basically, if you want to know how efficient your code is, you end up with a matrix with at least three dimensions:</p>

<ul>
<li>Prolog implementation (SWI-Prolog, SICSTUS, YAP, Gnu-Prolog...)</li>
<li>Data structure and algorithm used</li>
<li>Facilities provided by the implementation</li>
</ul>

<p>You will end up having some wholes in the matrix. Example: what is the best way to read line-based input, do something with each line, and output it? Read line by line, do the thing, output? Read all at once, do everything in memory, output at once? Use a DCG? In SWI-Prolog, since version 7, you can do:</p>

<pre><code>read_string(In_stream, _, Input),
split_string(Input, "\n", "", Lines),
maplist(do_x, Lines, Xs),
atomics_to_string(Xs, "\n", Output),
format(Out_stream, "~s\n", Output)
</code></pre>

<p>This is concise and very efficient. Caveats:</p>

<ul>
<li>The available memory might be a bottle neck</li>
<li>Strings are not standard Prolog, so you are stuck with implementations that have them</li>
</ul>

<p>This is a very basic example, but it demonstrates at least the following difficulties in answering your question:</p>

<ul>
<li>Differences between implementations</li>
<li>Opinions on what is readable or idiomatic Prolog</li>
<li>Opinions on the importance of standards</li>
</ul>

<p>The example above doesn't even go into details about your problem, as for example what you do with each line. Is it just text? Do you need to parse the lines? Why are you not using a stream of Prolog terms instead? and so on.</p>

<h2>On efficiency measurements</h2>

<p>Don't use the number of steps in the tracer, or even the reported number of inferences. You really need to measure time, with a realistic input. Sorting with <code>sort/2</code>, for example, always counts as exactly one inference, no matter what is the length of the list being sorted. On the other hand, <code>sort/2</code> in any Prolog is about as efficient as a sort on your machine would ever get, so is that an issue? You can't know until you have measured the performance.</p>

<p>And of course, as long as you make an informed choice of an algorithm and a data structure, you can at the very least know the complexity of your solution. Doing an efficiency measurement is interesting only if you notice a <strong>discrepancy between what you expect and what you measure</strong>: obviously, there is a mistake. Either your complexity analysis is wrong, or your implementation is wrong, or even the Prolog implementation you are using is doing something unexpected.</p>

<p>On top of this, there is the inherent problem of high-level libraries. With some of the more complex approaches, you might not be able to easily judge what the complexity of a given solution might be (constraint logic programming, as in CHR and CLPFD, is a prime example). Most real problems that fit nicely to the approach will be much easier to write, and more efficient than you could ever do without considerable effort and very specific code. But get fancy enough, and your CHR program might not even want to compile any more.</p>

<h2>Unification in the head of the predicate</h2>

<p>This is not opinion-based any more. Just do the unifications in the head if you can. It is <em>more readable to a Prolog programmer</em>, and it is more efficient.</p>

<h2>PS</h2>

<p>"Learn Prolog Now!" is a good starting point, but nothing more. Just work your way through it and move on.</p>
Prolog predicate arguments: readability vs. efficiency
<p>I want to ask pros and cons of different Prolog representations in arguments of predicates.</p>

<p>For example in <a href="http://www.learnprolognow.org/lpnpage.php?pagetype=html&amp;pageid=lpn-htmlse16" rel="nofollow">Exercise 4.3</a>: <em>Write a predicate second(X,List) which checks whether X is the second element of List.</em> The solution can be:</p>

<pre><code>second(X,List):- [_,X|_]=List.
</code></pre>

<p>Or,</p>

<pre><code>second(X,[_,X|_]).
</code></pre>

<p>The both predicates would behave similarly. The first one would be more readable than the second, at least to me. But the second one uses more stacks during the execution (I checked this with <em>trace</em>).</p>

<p>A more complicated example is <a href="http://www.learnprolognow.org/lpnpage.php?pagetype=html&amp;pageid=lpn-htmlse11" rel="nofollow">Exercise 3.5</a>: <em>Binary trees are trees where all internal nodes have exactly two children. The smallest binary trees consist of only one leaf node. We will represent leaf nodes as leaf(Label) . For instance, leaf(3) and leaf(7) are leaf nodes, and therefore small binary trees. Given two binary trees B1 and B2 we can combine them into one binary tree using the functor tree/2 as follows: tree(B1,B2) . So, from the leaves leaf(1) and leaf(2) we can build the binary tree tree(leaf(1),leaf(2)) . And from the binary trees tree(leaf(1),leaf(2)) and leaf(4) we can build the binary tree tree(tree(leaf(1),  leaf(2)),leaf(4)). Now, define a predicate swap/2 , which produces the mirror image of the binary tree that is its first argument.</em>  The solution would be:</p>

<p>A2.1:</p>

<pre><code>swap(T1,T2):- T1=tree(leaf(L1),leaf(L2)), T2=tree(leaf(L2),leaf(L1)).
swap(T1,T2):- T1=tree(tree(B1,B2),leaf(L3)), T2=tree(leaf(L3),T3), swap(tree(B1,B2),T3).
swap(T1,T2):- T1=tree(leaf(L1),tree(B2,B3)), T2=tree(T3,leaf(L1)), swap(tree(B2,B3),T3).
swap(T1,T2):- T1=tree(tree(B1,B2),tree(B3,B4)), T2=tree(T4,T3), swap(tree(B1,B2),T3),swap(tree(B3,B4),T4).
</code></pre>

<p>Alternatively,</p>

<p>A2.2:</p>

<pre><code>swap(tree(leaf(L1),leaf(L2)), tree(leaf(L2),leaf(L1))).
swap(tree(tree(B1,B2),leaf(L3)), tree(leaf(L3),T3)):- swap(tree(B1,B2),T3).
swap(tree(leaf(L1),tree(B2,B3)), tree(T3,leaf(L1))):- swap(tree(B2,B3),T3).
swap(tree(tree(B1,B2),tree(B3,B4)), tree(T4,T3)):- swap(tree(B1,B2),T3),swap(tree(B3,B4),T4).
</code></pre>

<p>The number of steps of the second solution was much less than the first one (again, I checked with <em>trace</em>).  But regarding the readability, the first one would be easier to understand, I think.</p>

<p>Probably the readability depends on the level of one's Prolog skill. I am a learner level of Prolog, and am used to programming with C++, Python, etc. So I wonder if skillful Prolog programmers agree with the above readability.</p>

<p>Also, I wonder if the number of steps can be a good measurement of the computational efficiency.</p>

<p>Could you give me your opinions or guidelines to design predicate arguments?</p>

<hr>

<p>EDITED.</p>

<p>According to the advice from @coder, I made a third version that consists of a single rule:</p>

<p>A2.3:</p>

<pre><code>swap(T1,T2):-
    ( T1=tree(leaf(L1),leaf(L2)), T2=tree(leaf(L2),leaf(L1)) );
    ( T1=tree(tree(B1,B2),leaf(L3)), T2=tree(leaf(L3),T3), swap(tree(B1,B2),T3) );
    ( T1=tree(leaf(L1),tree(B2,B3)), T2=tree(T3,leaf(L1)), swap(tree(B2,B3),T3) );
    ( T1=tree(tree(B1,B2),tree(B3,B4)), T2=tree(T4,T3), swap(tree(B1,B2),T3),swap(tree(B3,B4),T4) ).
</code></pre>

<p>I compared the number of steps in <em>trace</em> of each solution:</p>

<ul>
<li>A2.1: 36 steps</li>
<li>A2.2: 8 steps</li>
<li>A2.3: 32 steps</li>
</ul>

<p>A2.3 (readable single-rule version) seems to be better than A2.1 (readable four-rule version), but A2.2 (non-readable four-rule version) still outperforms.</p>

<p>I'm not sure if the number of steps in <em>trace</em> is reflecting the actual computation efficiency.
There are less steps in A2.2 but it uses more computation cost in pattern matching of the arguments.
So, I compared the execution time for 40000 queries (each query is a complicated one, <em>swap(tree(tree(tree(tree(leaf(3),leaf(4)),leaf(5)),tree(tree(tree(tree(leaf(3),leaf(4)),leaf(5)),leaf(4)),leaf(5))),tree(tree(leaf(3),tree(tree(leaf(3),leaf(4)),leaf(5))),tree(tree(tree(tree(leaf(3),leaf(4)),leaf(5)),leaf(4)),leaf(5)))), _).</em> ).  The results were almost the same (0.954 sec, 0.944 sec, 0.960 sec respectively).  This is showing that the three reresentations A2.1, A2.2, A2.3 have close computational efficiency.
Do you agree with this result? (Probably this is a case specific; I need to vary the experimental setup).</p>