How is Sequence[Range[5], 3, 2] // Partition@# & parsed?

This is not about parsing, it's about evaluation.

Consider

f[Sequence[1,2]]

which evaluates to f[1,2], and compare with

f[#]&[Sequence[1,2]]

which first evaluates to

f[#]&[1,2]

then to

f[1]

because only #1 (i.e. "#") appears in the pure function and #2 is discarded.

You could use ## instead. f[##]&[1, 2] evaluates to f[1,2].


In order to observe the evaluation, compare the output of

TracePrint[Sequence[Range[5], 3, 2] // Partition@# &]

with that of the original,

TracePrint[Partition@Sequence[Range[5], 3, 2]]

It becomes clear that there's a term (Partition[#1]&)[{1,2,3,4,5},3,2] appearing, which then becomes Partition[{1,2,3,4,5}], which is not what's desired (Partition needs to be given more than just the first argument #1); the original instead does Partition[{1,2,3,4,5},3,2].

As @szabolcs says, replacing # with ## does the trick:

TracePrint[Sequence[Range[5], 3, 2] // Partition@## &]

gives the right answer.


For longer chains of operations, and if the application will allow, it may be better to avoid trying to pass sequences through a pipeline. The issue is that sequences will, in general, require special handling at each step. On the other hand, lists pass through pipelines easily and can be converted to sequences as necessary using Apply or ## -- typically only on the terminal step.

Consider:

{Range[5], 3, 2} // Apply[Partition]

or, with a couple of additional steps:

{2, x, Range[5]} // ReplaceAll[x -> 3] // Reverse // Apply[Partition]

The latter example would be quite awkward to express if a sequence were being passed through the pipeline. Something like:

Sequence[2, x, Range[5]] //
Sequence @@ ReplaceAll[{##}, x -> 3] & //
Sequence @@ Reverse[{##}] & //
Partition[##] &

Notice how the sequence was temporarily converted to a list within each step, only to be converted back to a sequence afterwards. It is simpler to just pass lists through all the way until the end.