title: How to create bidirectional predicates in Prolog?
body: <p>In Prolog, there are predicates that are <em>bidirectional</em> (or even <em>"multidirectional"</em>), in the sense that one can split the set of variables into input and output variables in many different ways. For example, the predicate <code>number_string</code> acts like a bijection in both directions:</p>
  
  <pre><code>number_string(N, "42"). % finds solution N = 42
  number_string(42, S).   % finds solution S = "42"
  </code></pre>
  
  <p>However, this wonderful property does not seem to be preserved by the conjunction of clauses. For example, consider the following two predicates, which simply translate strings like <code>3x^2</code> into pieces of an abstract syntax tree like <code>term(3,2)</code>:</p>
  
  <pre><code>parse_stuff(String, term(Coeff, Pow)) :- 
    string_concat(CoeffStr, MonomialStr, String),
    string_concat("x^", PowStr, MonomialStr),
    number_string(Coeff, CoeffStr),
    number_string(Pow, PowStr).
  
  write_stuff(String, term(Coeff, Pow)) :- 
    number_string(Pow, PowStr),
    number_string(Coeff, CoeffStr),
    string_concat("x^", PowStr, MonomialStr),
    string_concat(CoeffStr, MonomialStr, String).
  </code></pre>
  
  <p>Both predicates are exactly the same, except that the order of the defining clauses on the right hand side is reversed. All clauses on the right hand side are themselves bidirectional. </p>
  
  <p>Here is an example session:</p>
  
  <pre><code>?- parse_stuff("3x^2", X).
  X = term(3, 2).
  
  ?- parse_stuff(X, term(3, 2)).
  ERROR: string_concat/3: Arguments are not sufficiently instantiated
  
  ?- write_stuff(X, term(3, 2)).
  X = "3x^2".
  
  ?- write_stuff("3x^2", X).
  ERROR: number_string/2: Arguments are not sufficiently instantiated
  </code></pre>
  
  <p>Both predicates work only in one way, although they both are obviously bijections, which is pretty sad.</p>
  
  <p>The question consists of two parts (there are two requirements: easy to use, easy to maintain):</p>
  
  <ol>
  <li>Is there any robust way to build bidirectional predicates in Prolog? </li>
  <li>Is it possible to avoid code-duplication (that is, maintaining two versions: one normal, one reversed)?</li>
  </ol>
  
  <p>Maybe there is some flag that tells "reverse the order of clauses if necessary"?</p>
  
  <p>I'm currently using SWI-Prolog 7.1.x, if it's relevant.</p>
  
  <hr>
  
  <p><a href="https://stackoverflow.com/a/29952316/2707792"><strong>↓ Jump to my own answer ↓</strong></a></p>