Why were there no parentheses?

In the following DCG, expected a set of parentheses around the last two values, but they are missing in the result; don’t know why?

:- use_module(library(dcg/basics)).

test(Evidence,Rest) :-
    Input = "ECO:0000269|PubMed:24603684.",
    string_codes(Input,Input_codes),
    DCG = evidence_item(Evidence),
    phrase(DCG,Input_codes,Rest).

evidence_item((Eco,Source)) -->
    evidence_code_ontology(Eco),
    evidence_source(Source),
    ".".

evidence_code_ontology(ECO) -->
    "ECO:",
    number(ECO_number),
    { ECO = (eco,ECO_number) }.

evidence_source(Source) -->
    "|",
    "PubMed:",
    string_without(".",Source_id_codes),
    {
        string_codes(Source_id,Source_id_codes),
        Source = (pub_med,Source_id)
    }.

Result:

?- test(Evidence,Rest).
Evidence =  ((eco, 269), pub_med, "24603684"),
Rest = [].

Expected Result:

?- test(Evidence,Rest).
Evidence =  ((eco, 269), (pub_med, "24603684")),
Rest = [].

Notice that for the first set of parentheses

(eco, 269)

this code worked,

ECO = (eco,ECO_number)

however for the second missing set of parentheses

pub_med, "24603684"

this code did NOT work

Source = (pub_med,Source_id)

EDIT 1

Here are some test/examples using write_canonical/1 I did in trying to understand this. Also reading ISO/IEC 13211-1


?- write_canonical(((eco, 269), (pub_med, 24603684))).
','(','(eco,269),','(pub_med,24603684))
true.

?- write_canonical(((eco, 269), pub_med, 24603684)).
','(','(eco,269),','(pub_med,24603684))
true.

?- write_canonical((eco, 269)).
','(eco,269)
true.

?- write_canonical((pub_med, 24603684)).
','(pub_med,24603684)
true.

?- write_canonical({pub_med, 24603684}).
{','(pub_med,24603684)}
true.

?- write_canonical(((eco, 269), {pub_med, 24603684})).
','(','(eco,269),{','(pub_med,24603684)})
true.

EDIT 2

Checking print/1

?- print(','(','(eco,269),','(pub_med,24603684))).
(eco,269),pub_med,24603684
true.

It should be in a FAQ :slight_smile: First of all, Prolog uses minimal parenthesis, quotes and spacing when writing a term. A term (a,b,c) is in fact

?- display((a,b,c)).
','(a,','(b,c))

Some more of these:

?- display(((a,b),(c,d))).
','(','(a,b),','(c,d))
?- display(((a,b),c,d)).
','(','(a,b),','(c,d))

Or, more direct

?- ((a,b),(c,d)) == ((a,b),c,d).
true.

For this reasons, using (a,b) for pairs is not a very good choice. Typically you either find a nice name for it, so that an X-Y pair becomes e.g., point(X,Y) or you use the -/2, e.g. a-b. A nice name has most advantages though:

  • You know what the tuple means
  • You can use it while matching clauses to distinguish it from other pairs.
1 Like

Note that in this particular case, I would probably return eco(Number) or pubmed(Number). Easy to create, compact and clear.