It occurred to me that I could think of two ways to generate a decreasing sequence. The built-in
i. will do this:
i. _7 6 5 4 3 2 1 0
But I could see a way to do it with self-reference
$: or with iterate
(<:^:*^:a:) 7 7 6 5 4 3 2 1 0
This essentially says "iterate gathering results"
^:a: "while non-zero"
<:. This differs slightly from
i. _7 because it includes the number 7, but whatever.
$: method is a little longer:
0:`(, $:@<:) @.* 7 7 6 5 4 3 2 1 0
Like any recursive function, we need a base case and an inductive case. Sentences like
in J give you case analysis, so a sentence like:
is a strong clue that your base case maps 0 to 0 and runs all positive numbers through
f, and that's what's happening here. So the next step is understanding
, $:@<:. This is about as simple as self-reference can get: we're making a hook (it means the same as
] , $:@<: if forks make more sense to you than hooks) basically using
, to append the current value with the result of the recursive call.
$:@<: says "apply myself after decrementing the argument".
This suggests an obvious way to get the increasing list, by just flipping around the arguments to
0:`($:@<: , ]) @.* 7 0 1 2 3 4 5 6 7
I'm sure the self-reference version is worse in performance terms, but there isn't as straightforward a way to flip it around like this, so this counts as an advantage here.
This is one thing where Prolog usually has a significant advantage over other languages, because you can make the relationship between palindromes and reflection explicit:
palindrome(X) :- reverse(X, X).
However, J is still able to beat this:
palindrome =: -: |.
Match the value with its reflection.