J has a built-in operator for this and related operations: ^:
(read ''power''). The particular variety of power you're looking for is when its right-hand argument is a boxed number (or numbers):
v^:(<n) initial_value
as in/:
>:@*:^:(<1+4) 2
2 5 26 677 458330
To make this a reusable verb (abstraction over n
and the initial value):
vv =: >:@*:@]^:(<@>:@[)
4 vv 2
2 5 26 677 458330
To make this a reusable adverb (abstracted over n
, the initial value, and v
):
V =: (@]) (^:(<@>:@[))
4 >:@*: V 2
2 5 26 677 458330
Note that ^:
also has other flavors. For example, if its right-hand argument is an unboxed number (or numbers), it just applies the function N times and produces the final value, rather than building up a vector of intermediate values.
Or, if its right-hand argument is infinite, it will apply the function to its fixed point. Or, combining these two observations, if its right-hand argument is boxed and infinite, it applies the function to its fixed point, building a vector of intermediate values along the way. And plenty of other neat tricks.
PS: Composing the function >:
with the function *:
using @
as in >:@*:
will correctly produce the input squared plus one.
However, since @
is defined to act like an assembly line, passing each output of *:
to >:
individually, the latter verb (increment) will be invoked #y
times. You could get the same result, more efficiently, using @:
("atop") in place of @
("at").
As a composing operator, @:
is more like a hopper than an assembly line: it waits for *:
finish processing completely, collects all its results together, and passes them to >:
in one go.
Given J's array oriented nature, the rule of thumb is "think big". That is, let each primitive see as much data as possible, and let the interpreter manage the details. While you're learning J, it might be worth adopting "use @: instead of @" as a blanket rule, until you get a handle of the nuances.