4
$\begingroup$

For learning purposes, I want to rewrite the following

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

{{1,2,3},{3,4,5}}

into another one

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

Partition::argbu: Partition called with 1 argument; between 2 and 6 arguments are expected. Partition[{1,2,3,4,5}]

However, the latter does not produce what the former does.

Question

What do I have to do to fix the latter to produce what the former does?

$\endgroup$
6
$\begingroup$

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].

$\endgroup$
  • $\begingroup$ Is it possible to hold the Sequence to prevent it from splicing in Sequence[Range[5], 3, 2] // Partition@# &? I just want to elaborate other methods if any. $\endgroup$ – Artificial Hairless Armpit Feb 11 at 13:32
  • 1
    $\begingroup$ @ArtificialStupidity Add the SequenceHold or other appropriate attribute to your pure function. Function[x, Partition[x], SequenceHold][Sequence[Range[5], 3, 2]]. Or use Unevaluated: Partition[#] &[Unevaluated@Sequence[Range[5], 3, 2]] $\endgroup$ – Szabolcs Feb 11 at 13:59
  • $\begingroup$ Thank you. I love Unevaluated. $\endgroup$ – Artificial Hairless Armpit Feb 11 at 14:11
5
$\begingroup$

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.

$\endgroup$
2
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ I like infix, for example, Sequence[a, b]~F~Sequence[c, d] that is only possible with Sequence I think. $\endgroup$ – Artificial Hairless Armpit Feb 11 at 16:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.