I’m using: SWI-Prolog version 8.1.17
I want the code to use sequence//3
or maybe sequence//5
from library(dcg/high_order)
to parse a string of integers separated by commas, like this: “1,2,3”.
First, the three-argument version, sequence(:Element, :Sep, ?List)
, documented as:
Match or generate a sequence of Element where each pair of elements is separated by Sep. When parsing , a matched Sep commits . The final element is not committed.
I’d expect:
?- use_module(library(dcg/basics)), use_module(library(dcg/high_order)).
true.
?- phrase(sequence(integer, ",", L), `1,2,3`).
L = [1, 2, 3].
But what I’m getting is:
?- phrase(sequence(integer, ",", L), `1,2,3`).
L = [1, 2, 3] ;
false.
I’d also expect (note the trailing comma in the input!):
?- phrase(sequence(integer, ",", L), `1,2,3,`, Rest).
L = [1, 2, 3],
Rest = [44].
But what I am getting is actually what I would have expected when the trailing comma is not there:
?- phrase(sequence(integer, ",", L), `1,2,3,`, Rest).
L = [1, 2, 3],
Rest = [].
No choice point left behind, either.
And when we then take sequence(:Start, :Element, :Sep, :End, ?List)
, documented as:
Match or generate a sequence of Element enclosed by Start end End, where each pair of elements is separated by Sep. More formally, it matches the following sequence:
Start (Element,Sep)*, End
So I would for example expect that this does what sequence//3
did in the last example above.
Expected:
?- phrase(sequence("", integer, ",", ",", L), `1,2,3,`).
L = [1, 2, 3].
but instead, I get:
?- phrase(sequence("", integer, ",", ",", L), `1,2,3,`).
false.
It follows the same logic as sequence//3
(so at least the two are consistent!):
?- phrase(sequence("", integer, ",", "", L), `1,2,3,`).
L = [1, 2, 3].
But then I am not sure if it is consistent with:
?- phrase(sequence("", integer, ",", "\n", L), `1,2,3\n`).
L = [1, 2, 3].
To summarize: the separator is also used as an “End” of the sequence, and then the predicate does not leave a choice point. In the 5-argument version, if the “End” is the same as the separator, we need to leave the End argument empty, but if it is different, we need to match it.
I am missing something relevant?
And a second issue: nesting of sequence
. It kinda works for me, but I am not sure how to make it “do what I mean”. I would like to have:
?- phrase(<something magical with a sequence inside a sequence to L>,
`1,2\n3,4\n5,6\n`).
L = [[1,2], [3,4], [5,6]].
The best I could do was:
?- phrase(sequence(sequence(integer, ","), "\n", L), `1,2\n3,4\n5,6\n`).
L = [[1, 2], [3, 4], [5, 6], []] ;
L = [[1, 2], [3, 4], [5, 6]].
How am I supposed to write it?