Changing length of PSeq array on every repeat?

More generally speaking, the repeats argument is usually evaluated with .value in the Patterns from classlib. That makes it possible to use “naked” functions for repeats but also streams/routines because .value for streams/routines is the same as .next. However .value for Patterns just returns the pattern.

r = r { 42.yield }; [r.value, r.value] // -> [ 42, nil ]
Pbind().value // -> a Pbind

Also .iter is a good shortcut synonym for .asStream on Patterns, but it can be a gotcha if you call it on an array if you didn’t intend to iterate over the array’s items but use it as a constant.

[1, 2].iter.next // -> 1
[1, 2].asStream.next // -> [ 1, 2 ]

But in your case

Pn(Pser((1..7), Pseq((7..2) ++ (2..7)).asStream), inf)

can be just

Pn(Pser((1..7), ((7..2) ++ (2..7)).iter))

(inf is the default repeats for Pn, so that’s redundant too.)

Also there are already defined methods for mirroring arrays

(7..2) ++ (2..7) == (7..2).mirror2

And the array pyramid methods can “directly” generate the same number patterns you want (in finite form of course), although it’s hard to remember the right invocations; their argument is an algorithm number!

n = 4 // use 7 for your original ex.; this is for shorter output
a = (n..2).mirror2
g = Pn(Pseries(1, 1, a.iter), a.size).iter.all // or
h = (1..n).pyramidg(3).drop(-1).mirror2.flatten
g == h // test

// pyramid(7) almost does what you want by itself
// but you have to remove the middle element
k = (1..n).pyramid(7); k.removeAt(k.size div: 2); k
k == g

There are also list comprehensions (actually generators as they return routines) in SC… which make some of that pyramid business more comprehensible …

(1..n).pyramidg(3).drop(-1)
// same as
{: (1..x), x <- (n..2) }.all

{: (1..x), x <- (n..2).mirror2 }.all.flatten
// same as
(1..n).pyramidg(3).drop(-1).mirror2.flatten

And a rather obscure/undocumented way of doing the same without flatten

{{; (1..x) do: _.yield, x <- (n..2).mirror2 }}.r.all 

Also this is a “flatMap” application, but then so all the pyramid functions basically…

(n..2).mirror2.collect((1.._)).flatten 

As a variation on that, “auto-flattening” can be done by producing a Pseq that has an array of Pseqs as its argument.

Pseq((n..2).mirror2.collect{|x| Pseq((1..x))}).iter.all 

In that last expression, using Pseries(1, 1, x) probably marginally more efficient than Pseq((1..x)) for longish things. On that angle though, the Pn(Pseries solution is even more efficient though; properly encapsulating the a variable looks something like

Plazy{var a = (n..2).mirror2; Pn(Pseries(1, 1, a.iter), a.size)}.iter.all

You can avoid generating/storing the array a too, although that looks pretty long to write as a constant-storage Pattern:

(
Plazy{
	var itr = (Pseries(n, -1, n-1) ++ Pseries(2, 1, n-1)).iter;
	Pn(Pseries(1, 1, itr), 2*n-2)
}.iter.all
)

Premature optimization :sweat: As it turns out, SC list comprehensions automatically detect and apply this kind of optimization.