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 As it turns out, SC list comprehensions automatically detect and apply this kind of optimization.