didoudiaz / gprolog

GNU Prolog
Other
106 stars 13 forks source link

Write option max_depth/1 differences #56

Open UWN opened 1 year ago

UWN commented 1 year ago

(After looking at other systems, it seems evident, that only SICStus, Ciao, XSB have a consistent way of handling this option and handling it the same way (modulo variable names and spaces). )

?- member(T,[1+2+3+4,[1,2,3,4],[_,_,_,_]]),between(0,5,D),write(D),write(' '),write_term(T,[max_depth(D)]),nl,false.

SICStus 4.8.0               GNU v1.6.0-rc-2-ga58f3cb

0 1+2+3+4                   0 ...
1 ... + ...                 1 ... + ...
2 ... + ... +4              2 ... + ... +4
3 ... + ... +3+4            3 ... + ... +3+4
4 1+2+3+4                   4 1+2+3+4
5 1+2+3+4                   5 1+2+3+4
0 [1,2,3,4]                 0 ...
1 [...|...]                 1 [...]
2 [1,2|...]                 2 [1,...]
3 [1,2,3|...]               3 [1,2,...]
4 [1,2,3,4]                 4 [1,2,3,...]
5 [1,2,3,4]                 5 [1,2,3,4]
0 [_1003,_1035,_1067,_1099] 0 ...
1 [_1003|...]               1 [...]
2 [_1003,_1035|...]         2 [_297,...]
3 [_1003,_1035,_1067|...]   3 [_297,_298,...]
4 [_1003,_1035,_1067,_1099] 4 [_297,_298,_299,...]
5 [_1003,_1035,_1067,_1099] 5 [_297,_298,_299,_300]
pmoura commented 1 year ago

A common issue seems to be counting depth for lists vs other compound terms.

pmoura commented 1 year ago

Results for LVM 6.3.0:

?- member(T,[1+2+3+4,[1,2,3,4],[_,_,_,_]]),between(0,5,D),write(D),write(' '),write_term(T,[max_depth(D)]),nl,false.
0 1+2+3+4
1 ... + ...
2 ... + ... +4
3 ... + ... +3+4
4 1+2+3+4
5 1+2+3+4
0 [1,2,3,4]
1 [1|...]
2 [1,2|...]
3 [1,2,3|...]
4 [1,2,3,4]
5 [1,2,3,4]
0 [_R1,_R2,_R3,_R4]
1 [_R1|...]
2 [_R1,_R2|...]
3 [_R1,_R2,_R3|...]
4 [_R1,_R2,_R3,_R4]
5 [_R1,_R2,_R3,_R4]
false.

Interesting difference between SICStus and LVM: 1 [...|...] vs 1 [1|...]. Trealla also outputs 1 [1|...].

UWN commented 1 year ago

Here is another view to understand some of the assumptions present. After all, a list is kind of a right-associative structure. So let's compare them (here Ciao) with 1^2^3^4^nil

?- member(T,[1+2+3+4,1^2^3^4^nil,[1,2,3,4],[_,_,_,_]]),between(0,5,D),write(D),write(' '),write_term(T,[max_depth(D)]),nl,false.
0 1+2+3+4
1 ... + ...
2 ... + ... +4
3 ... + ... +3+4
4 1+2+3+4
5 1+2+3+4
0 1^2^3^4^nil
1 ... ^ ...
2 1^ ... ^ ...
3 1^2^ ... ^ ...
4 1^2^3^ ... ^ ...
5 1^2^3^4^nil
0 [1,2,3,4]
1 [...|...]
2 [1,2|...]
3 [1,2,3|...]
4 [1,2,3,4]
5 [1,2,3,4]
0 [_18139,_18148,_18157,_18166]
1 [_18139|...]
2 [_18139,_18148|...]
3 [_18139,_18148,_18157|...]
4 [_18139,_18148,_18157,_18166]
5 [_18139,_18148,_18157,_18166]

no

While 1+2+3+4 and 1^2^3^4^nil seem to be uncontroversial, the question is now how this translates (or not) to the list syntax. Taken the example of the ^-list literally, D = 2 would have to be [1,...|...]. Well, who wants this? But then, why accept [...|...] in the case of D = 1?

UWN commented 1 year ago

The closer I look, the uglier it gets. And also the fewer the systems I can look at. Now there is only SICStus left...

| ?- nth0(I,[A+B+C+D,1+2+3+4,A^B^C^D^E,1^2^3^4^nil,[1,2,3,4],[A,B,C,D],[- -A,- -B,- -C,- -D],[[A,B,C,D]]],T),
     between(0,5,M), write(I-M), write(' '),
     write_term(T,[variable_names(['A'=A,'B'=B,'C'=C,'D'=D,'E'=E]),max_depth(M)]), nl, false.

SICStus                    GNU
0-0 A+B+C+D                0-0 A+B+C+D
0-1 ... +D                 0-1 ... + ...
0-2 ... +C+D               0-2 ... + ... +D
0-3 A+B+C+D                0-3 ... + ... +C+D
0-4 A+B+C+D                0-4 A+B+C+D
0-5 A+B+C+D                0-5 A+B+C+D
1-0 1+2+3+4                1-0 1+2+3+4
1-1 ... + ...              1-1 ... + ...
1-2 ... + ... +4           1-2 ... + ... +4
1-3 ... + ... +3+4         1-3 ... + ... +3+4
1-4 1+2+3+4                1-4 1+2+3+4
1-5 1+2+3+4                1-5 1+2+3+4
2-0 A^B^C^D^E              2-0 A^B^C^D^E
2-1 A^ ...                 2-1 ... ^ ...
2-2 A^B^ ...               2-2 A^ ... ^ ...
2-3 A^B^C^ ...             2-3 A^B^ ... ^ ...
2-4 A^B^C^D^E              2-4 A^B^C^ ... ^ ...
2-5 A^B^C^D^E              2-5 A^B^C^D^E
3-0 1^2^3^4^nil            3-0 1^2^3^4^nil
3-1 ... ^ ...              3-1 ... ^ ...
3-2 1^ ... ^ ...           3-2 1^ ... ^ ...
3-3 1^2^ ... ^ ...         3-3 1^2^ ... ^ ...
3-4 1^2^3^ ... ^ ...       3-4 1^2^3^ ... ^ ...
3-5 1^2^3^4^nil            3-5 1^2^3^4^nil
4-0 [1,2,3,4]              4-0 [1,2,3,4]
4-1 [...|...]              4-1 [...]
4-2 [1,2|...]              4-2 [1,...]
4-3 [1,2,3|...]            4-3 [1,2,...]
4-4 [1,2,3,4]              4-4 [1,2,3,...]
4-5 [1,2,3,4]              4-5 [1,2,3,4]
5-0 [A,B,C,D]              5-0 [A,B,C,D]
5-1 [A|...]                5-1 [...]
5-2 [A,B|...]              5-2 [A,...]
5-3 [A,B,C|...]            5-3 [A,B,...]
5-4 [A,B,C,D]              5-4 [A,B,C,...]
5-5 [A,B,C,D]              5-5 [A,B,C,D]
6-0 [- -A,- -B,- -C,- -D]  6-0 [- -A,- -B,- -C,- -D]
6-1 [...|...]              6-1 [...]
6-2 [- ...,- ...|...]      6-2 [- ...,...]
6-3 [- -A,- -B,- ...|...]  6-3 [- - ...,- ...,...]
6-4 [- -A,- -B,- -C,- ...] 6-4 [- -A,- - ...,- ...,...]
6-5 [- -A,- -B,- -C,- -D]  6-5 [- -A,- -B,- - ...,- ...]
7-0 [[A,B,C,D]]            7-0 [[A,B,C,D]]
7-1 [...]                  7-1 [...]
7-2 [[A|...]]              7-2 [[...]]
7-3 [[A,B|...]]            7-3 [[A,...]]
7-4 [[A,B,C|...]]          7-4 [[A,B,...]]
7-5 [[A,B,C,D]]            7-5 [[A,B,C,...]]

4-1 is problematic in SICStus, not because of 5-1 but because of 4-2. 6-4, I would say (so far), that all elements of a list should be printed with the same depth. But in any case, these two questions are a bit open. So for the moment, most relevant is that the terms can still be used reconstruct a term which has the original term as an instance.

pmoura commented 1 year ago

Indeed we should see 4-1 [1|...] for consistency.

pmoura commented 1 year ago

Both CxProlog and LVM output 4-1 [1|...].

didoudiaz commented 1 year ago

A general remark: this option is to help the user to limit large term display by giving it "an idea" of what the term is. The ellipsis meaning "followed by something I suppose you can guess more or less (else increase the depth)".

Keeping this in mind, as I user I prefer [...] to [...|...] which is just more cumbersome and add no information (basically I understand that my term is a list). Similarly, I find [1,...] more intuitive than [1|...] (basically I understand my term is a list whose the first element is 1).

pmoura commented 1 year ago

A general remark: this option is to help the user to limit large term display by giving it "an idea" of what the term is. The ellipsis meaning "followed by something I suppose you can guess more or less (else increase the depth)".

Agree. E.g. I use it in the Logtalk debugger which allows the user to set the max term depth.

Keeping this in mind, as I user I prefer [...] to [...|...] which is just more cumbersome and add no information (basically I understand that my term is a list). Similarly, I find [1,...] more intuitive than [1|...] (basically I understand my term is a list whose the first element is 1).

Both tell the user that it's a list whose the first element is 1. I have no strong preference here other that consistency and ideally a common output for common case among systems.

didoudiaz commented 1 year ago

I don't find SICStus coherent (with itself) between 0-1,0-2,0-3 and 1-1,1-2,1-3. It seems variables are treated differently (why not all atomics also ?). This seems confirmed by 2-1,2-2,2-3 wrt 3-1,3-2,3-3.

UWN commented 1 year ago

Yes, variables are treated differently! A ... stands for a non-variable term. And why not all atomic terms, they can become quite large. Also replacing a variable by a non-variable term like ... looks rather like an expansion not an abbreviation.

0-1,0-2,0-3 is quite coherent if you count the operators. In 0-3 there are already variables that do not need to be abbreviated.

What is really important is that the abbreviated term can be used to reconstruct (partially) the original term. Think of 4-1 in GNU. This [...] suggests that there is a one-element list. But this is not the case. In this case it is important to insist that we see only the front of a list. This [...|...] or [1|...]. If this property is preserved, such abbreviated terms can be used for testing. Otherwise it is just misdirection for the user. So the very exact depth and the like are less important compared to this property.

UWN commented 1 year ago

Or see this from another level: Before printing, replace some non-variable subterms by ..., then print without any depth restriction. That's it. In this manner it is guaranteed that the ... stands for a non-variable subterm and not, say for several of them.

didoudiaz commented 1 year ago

A ... stands for a non-variable term.

Interesting ? Do you have a reference for this definition ?

Yes, variables are treated differently!

On which systems (other than Sicstus) is it the case ?

And why not all atomic terms, they can become quite large.

Variable names can also be rather large, most of the time (in particular in debugging session) they are written as '_addr, e.g._35298728` (SWI). Many integers are shorter than this, why not display them too ?

This [...] suggests that there is a one-element list.

IMHO [...|...] does not really bring anything useful for the user but really pollutes the output (if one wants to know more about the content of the list, he simply increases the depth).

UWN commented 1 year ago

A ... stands for a non-variable term.

Interesting ? Do you have a reference for this definition ?

When a variable is replaced by a non-variable term this is called a substitution. See any textbook.

Yes, variables are treated differently!

On which systems (other than Sicstus) is it the case ?

See above Ciao and XSB. If you find another system, try:

?- (Z=1;Z=2;Z=3),write_term(A+B+C+D,[max_depth(Z)]),nl,false.

And why not all atomic terms, they can become quite large.

Variable names can also be rather large, most of the time (in particular in debugging session) they are written as '_addr, e.g._35298728` (SWI). Many integers are shorter than this, why not display them too ?

You need some consistency in behavior. And, just to reiterate: substitution is a well known operation on variables. So if you are replacing a variable by ... that looks like a substitution.

And printing a very longish variable like the one you mention is a problem with this system. Also note that printing unnamed variables is a problem in itself. To my knowledge, only SICStus has found a way to handle this. But let's leave that out of the discussion here, since you do not have GC.

This [...] suggests that there is a one-element list.

IMHO [...|...] does not really bring anything useful for the user but really pollutes the output (if one wants to know more about the content of the list, he simply increases the depth).

What do you prefer: a term like [...] which incorrectly suggests that this is a one-element list. Or an output which contains less-than-you-expect information, but which is accurate?

UWN commented 1 year ago

Maybe printing atomic terms that are shorter or equal to ... makes sense. In this manner, one could also print [...] when there is a one-element list. After all, this does not violate the assumption that ... stands for a non-variable term.

UWN commented 1 year ago

Also note that printing unnamed variables is a problem in itself.

To be precise, repeated printing of terms with the same variables is a problem in itself. As for ISO, naming of unnamed shared variables is consistent only within a single invocation of write_term/2. But even two otherwise identical write_term/2 goals in a row may use such internal variable names differently.

didoudiaz commented 1 year ago

A ... stands for a non-variable term.

Interesting ? Do you have a reference for this definition ?

When a variable is replaced by a non-variable term this is called a substitution. See any textbook.

My question is not about substitution (which we all know obviously). My question is about "... stands for non variable term". I never saw the non variable feature explicitly mentioned and thus I'm interested in any pointer (there is generally few info about max_depth option and ...).

UWN commented 1 year ago

That it is used here is Prolog lore. One purpose of standardization is to make these things explicit.

UWN commented 1 year ago

In very old systems, this feature is only available with the debugger and the option is called printdepth. The oldest version that prints lists correctly that I can get hold of right now is 3.8.4 of about 2000-07 (or earlier). And the newest version that does the abbreviation incorrect as GNU is 0.7 of 1991-11. The manual of 3.7.1 of 1997-11 has it still incorrect in an example. And in 3.8 of 1999-10 this example is gone.

didoudiaz commented 1 year ago

Thanks for these pointers and for the test-set you provided. It helped me to improve my implementation on the emission of ... inside lists. NB variables are still not treated differently. Now:

| ?- nth0(I,[A+B+C+D,1+2+3+4,A^B^C^D^E,1^2^3^4^nil,[1,2,3,4],[A,B,C,D],[- -A,- -B,- -C,- -D],[[A,B,C,D]]],T),
     between(0,5,M), write(I-M), write(' '),
     write_term(T,[variable_names(['A'=A,'B'=B,'C'=C,'D'=D,'E'=E]),max_depth(M)]), nl, false.

SICStus                    GNU
0-0 A+B+C+D                0-0 A+B+C+D          
0-1 ... +D                 0-1 ... + ...            
0-2 ... +C+D               0-2 ... + ... +D     
0-3 A+B+C+D                0-3 ... + ... +C+D       
0-4 A+B+C+D                0-4 A+B+C+D          
0-5 A+B+C+D                0-5 A+B+C+D          
1-0 1+2+3+4                1-0 1+2+3+4          
1-1 ... + ...              1-1 ... + ...            
1-2 ... + ... +4           1-2 ... + ... +4     
1-3 ... + ... +3+4         1-3 ... + ... +3+4       
1-4 1+2+3+4                1-4 1+2+3+4          
1-5 1+2+3+4                1-5 1+2+3+4          
2-0 A^B^C^D^E              2-0 A^B^C^D^E            
2-1 A^ ...                 2-1 ... ^ ...            
2-2 A^B^ ...               2-2 A^ ... ^ ...     
2-3 A^B^C^ ...             2-3 A^B^ ... ^ ...       
2-4 A^B^C^D^E              2-4 A^B^C^ ... ^ ...     
2-5 A^B^C^D^E              2-5 A^B^C^D^E            
3-0 1^2^3^4^nil            3-0 1^2^3^4^nil          
3-1 ... ^ ...              3-1 ... ^ ...            
3-2 1^ ... ^ ...           3-2 1^ ... ^ ...     
3-3 1^2^ ... ^ ...         3-3 1^2^ ... ^ ...       
3-4 1^2^3^ ... ^ ...       3-4 1^2^3^ ... ^ ...     
3-5 1^2^3^4^nil            3-5 1^2^3^4^nil          
4-0 [1,2,3,4]              4-0 [1,2,3,4]            
4-1 [...|...]              4-1 [1|...]          
4-2 [1,2|...]              4-2 [1,2|...]            
4-3 [1,2,3|...]            4-3 [1,2,3|...]          
4-4 [1,2,3,4]              4-4 [1,2,3,4]            
4-5 [1,2,3,4]              4-5 [1,2,3,4]            
5-0 [A,B,C,D]              5-0 [A,B,C,D]            
5-1 [A|...]                5-1 [A|...]          
5-2 [A,B|...]              5-2 [A,B|...]            
5-3 [A,B,C|...]            5-3 [A,B,C|...]          
5-4 [A,B,C,D]              5-4 [A,B,C,D]            
5-5 [A,B,C,D]              5-5 [A,B,C,D]            
6-0 [- -A,- -B,- -C,- -D]  6-0 [- -A,- -B,- -C,- -D]    
6-1 [...|...]              6-1 [- ...|...]          
6-2 [- ...,- ...|...]      6-2 [- - ...,- ...|...]      
6-3 [- -A,- -B,- ...|...]  6-3 [- -A,- - ...,- ...|...] 
6-4 [- -A,- -B,- -C,- ...] 6-4 [- -A,- -B,- - ...,- ...]    
6-5 [- -A,- -B,- -C,- -D]  6-5 [- -A,- -B,- -C,- - ...] 
7-0 [[A,B,C,D]]            7-0 [[A,B,C,D]]          
7-1 [...]                  7-1 [[A|...]]            
7-2 [[A|...]]              7-2 [[A,B|...]]          
7-3 [[A,B|...]]            7-3 [[A,B,C|...]]        
7-4 [[A,B,C|...]]          7-4 [[A,B,C,D]]          
7-5 [[A,B,C,D]]        7-5 [[A,B,C,D]]

As mentioned by both of you, 4-1 is not consistent in sicstus thus the "shift" in displays between both systems (which does not appear with vars which are treated differently in sisctus).

UWN commented 1 year ago

I hope you reconsider your decision to go against this treatment of variables. This simply only means that your systems gets tested less. Like for cases you did not consider [[[[[[[[A,B,C,D]]]]]]]]] nor:


| ?- T=s(T), write_term(T,[max_depth(3)]),false.
s(s(s(...))) % sto, but good

no
| ?- T=[T], write_term(T,[max_depth(3)]),false. 
[[[[[[[[[[[[ % sto, unexpected...
didoudiaz commented 1 year ago

What is the output of the following goal (try to reply before testing any system):

write_term(f(1,2,3),[max_depth(1)]).

All systems I have tried (including ciao, sisctus, ... exception is swi) show f(...) which is very similar to my initial [...] for an incomplete list. According to you, they should output f(...,...,...). This implies max_depth option is ineffective on large arity terms, e.g. ILP.

UWN commented 1 year ago

I agree with your view. Yes, I think that f(...,...,...) should be the result, or a ... for it all.

UWN commented 1 year ago

So maybe replace such very large terms earlier than the indicated depth. But what is most crucial is that all of it is somewhat testable. That is, replace the dots by variables and then subsumes_term(Generalized, Original) must hold.

didoudiaz commented 1 year ago

or a ... for it all.

NB: ... does not respect the "replace the dots by variables and then subsumes_term(Generalized, Original) must hold". This remains testable (obviously not with a simple subsumes_term).

But it allows to shorten large arity terms. In that case, an additional possibility is to limit the number of arguments of a structure displayed (as done for lists) as follows:

| ?- write_term(f(1,2,3,4),[max_depth(1)]).
f(1,...)

| ?- write_term(f(1,2,3,4),[max_depth(2)]).
f(1,2,...)

| ?- write_term(f(1,2,3,4),[max_depth(3)]).
f(1,2,3,...)
UWN commented 1 year ago

SICStus:

| ?- functor(F,f,100),write_term(F,[max_depth(1)]).
f(...)
F = ... ? 
yes
| ?- functor(F,f,100),write_term(F,[max_depth(2)]).
f(_1709,_1711,_1713,_1715,_1717,_1719,_1721,_1723,_1725,_1727,_1729,_1731,_1733,_1735,_1737,_1739,_1741,_1743,_1745,_1747,_1749,_1751,_1753,_1755,_1757,_1759,_1761,_1763,_1765,_1767,_1769,_1771,_1773,_1775,_1777,_1779,_1781,_1783,_1785,_1787,_1789,_1791,_1793,_1795,_1797,_1799,_1801,_1803,_1805,_1807,_1809,_1811,_1813,_1815,_1817,_1819,_1821,_1823,_1825,_1827,_1829,_1831,_1833,_1835,_1837,_1839,_1841,_1843,_1845,_1847,_1849,_1851,_1853,_1855,_1857,_1859,_1861,_1863,_1865,_1867,_1869,_1871,_1873,_1875,_1877,_1879,_1881,_1883,_1885,_1887,_1889,_1891,_1893,_1895,_1897,_1899,_1901,_1903,_1905,_1907)
F = ... ? 
yes

F = ... abbreviated by myself So this only works in one case, and in the other very similar case, the full term is shown.

UWN commented 1 year ago

NB: ... does not respect the "replace the dots by variables and then subsumes_term(Generalized, Original) must hold". This remains testable (obviously not with a simple subsumes_term).

Why not?

didoudiaz commented 1 year ago
| ?- write_term(f(1,2,3),[max_depth(1)]).
f(...)
yes
| ?- subsumes_term(f(X),f(1,2,3)).
no
UWN commented 1 year ago

Ah, sorry. I misunderstood you. No, exactly because of this, I think these wrongly abbreviated terms do not serve much purpose. And as you have seen for SICStus, its use is quite inconsequential.

didoudiaz commented 1 year ago

Fixed.

| ?- nth0(I,[A+B+C+D,1+2+3+4,A^B^C^D^E,1^2^3^4^nil,[1,2,3,4],[A,B,C,D],[- -A,- -B,- -C,- -D],[[A,B,C,D]]],T),
     between(0,5,M), write(I-M), write(' '),
     write_term(T,[variable_names(['A'=A,'B'=B,'C'=C,'D'=D,'E'=E]),max_depth(M)]), nl, false.

SICStus                     GNU
0-0 A+B+C+D                 0-0 A+B+C+D
0-1 ... +D                  0-1 ... +D
0-2 ... +C+D                0-2 ... +C+D
0-3 A+B+C+D                 0-3 A+B+C+D
0-4 A+B+C+D                 0-4 A+B+C+D
0-5 A+B+C+D                 0-5 A+B+C+D
1-0 1+2+3+4                 1-0 1+2+3+4
1-1 ... + ...               1-1 ... + ...
1-2 ... + ... +4            1-2 ... + ... +4
1-3 ... + ... +3+4          1-3 ... + ... +3+4
1-4 1+2+3+4                 1-4 1+2+3+4
1-5 1+2+3+4                 1-5 1+2+3+4
2-0 A^B^C^D^E               2-0 A^B^C^D^E
2-1 A^ ...                  2-1 A^ ...
2-2 A^B^ ...                2-2 A^B^ ...
2-3 A^B^C^ ...              2-3 A^B^C^ ...
2-4 A^B^C^D^E               2-4 A^B^C^D^E
2-5 A^B^C^D^E               2-5 A^B^C^D^E
3-0 1^2^3^4^nil             3-0 1^2^3^4^nil
3-1 ... ^ ...               3-1 ... ^ ...
3-2 1^ ... ^ ...            3-2 1^ ... ^ ...
3-3 1^2^ ... ^ ...          3-3 1^2^ ... ^ ...
3-4 1^2^3^ ... ^ ...        3-4 1^2^3^ ... ^ ...
3-5 1^2^3^4^nil             3-5 1^2^3^4^nil
4-0 [1,2,3,4]               4-0 [1,2,3,4]
4-1 [...|...]               4-1 [1|...]
4-2 [1,2|...]               4-2 [1,2|...]
4-3 [1,2,3|...]             4-3 [1,2,3|...]
4-4 [1,2,3,4]               4-4 [1,2,3,4]
4-5 [1,2,3,4]               4-5 [1,2,3,4]
5-0 [A,B,C,D]               5-0 [A,B,C,D]
5-1 [A|...]                 5-1 [A|...]
5-2 [A,B|...]               5-2 [A,B|...]
5-3 [A,B,C|...]             5-3 [A,B,C|...]
5-4 [A,B,C,D]               5-4 [A,B,C,D]
5-5 [A,B,C,D]               5-5 [A,B,C,D]
6-0 [- -A,- -B,- -C,- -D]   6-0 [- -A,- -B,- -C,- -D]
6-1 [...|...]               6-1 [...|...]
6-2 [- ...,- ...|...]       6-2 [- ...|...]
6-3 [- -A,- -B,- ...|...]   6-3 [- -A,- ...|...]
6-4 [- -A,- -B,- -C,- ...]  6-4 [- -A,- -B,- ...|...]
6-5 [- -A,- -B,- -C,- -D]   6-5 [- -A,- -B,- -C,- ...]
7-0 [[A,B,C,D]]             7-0 [[A,B,C,D]]
7-1 [...]                   7-1 [...]
7-2 [[A|...]]               7-2 [[A|...]]
7-3 [[A,B|...]]             7-3 [[A,B|...]]
7-4 [[A,B,C|...]]           7-4 [[A,B,C|...]]
7-5 [[A,B,C,D]]             7-5 [[A,B,C,D]]