Back to: Vocabulary

Loopless Programming

Looping - performing a computation repeatedly - is what programs do. In most computer languages, all loops are expressed by one of two statements:

Do While - repeat a code block until a condition is met

- repeat a code block until a condition is met For - repeat a code block, with a loop index indicating how many times the block has been repeated.

Many modern languages have iterators, which slightly streamline the For loop, but without addressing its fundamental deficiencies.

Programmers trained on scalar languages have spent many years internalizing the Do-While and For paradigms. Discarding these paradigms is the biggest re-think they need to make when they learn J.

But re-think they must. J's approach to iteration is vastly better than other languages'. Consider this example problem: add each number in a list x to each number in the corresponding row of a two-dimensional array y . A J programmer would write

x + y

A C programmer would write

for(i = 0;i<sizeof(x)/sizeof(x[0]);++i) for(j = 0;j<sizeof(y)/sizeof(y[0]);++j) z = x[i] + y[i][j]; } }

Why is J's way better?

Shorter is easier to understand, once you know the language.

( x + y ) is an expression rather than a statement . The J programmer can embed ( x + y ) in a larger expression, perhaps a matrix multiplication ( w +/ . * (x + y) ) which adds the equivalent of three more nested loops, but is still a single expression. Expressions can be combined; statements cannot.

) is an rather than a . The J programmer can embed ( ) in a larger expression, perhaps a matrix multiplication ( ) which adds the equivalent of three more nested loops, but is still a single expression. Expressions can be combined; statements cannot. The C code requires the programmer to get down to the level of individual array elements. A J programmer thinks in terms of entire arrays, combining them using array-savvy primitives.

To think like a J programmer, you need to know the following tricks behind loopless programming.

Types Of Loops

Why is J so effective? Because almost all the loops you ever need fall into one of a few categories.

J has modifiers for each category. By connecting different modifiers together, you can create almost any looping structure you need.

Boolean Lists

Behind many loops is the idea of testing each item of an array z and then taking some action, or not, depending on whether the test passed or not.

You might:

count the values that pass the test

add up all the values that pass the test

delete all the values that don't pass the test

create a series of totals, resetting the total at each item that passes the test

In J we do this by creating a Boolean list, one value ( 0 or 1 ) per item of z

Instead of individually testing each item of the array, we do all the tests at once, getting the results back as a single Boolean list. Then we compute what we're looking for.

Create this Boolean list by applying a logic primitive (verb) to the target array: z . Most primitive verbs are array-savvy, so this automatically applies the verb to each item of z .

z =. 3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 z > 5 0 0 0 0 0 1 0 1 0 0 0 1 1 1 1

An important fact about a Boolean list is that the Boolean values are ordinary numbers 0 or 1 . You can do arithmetic with them.

Examples

1. How many numbers are greater than 5?

+/ z>5 6

+/y adds up the numbers in y - the number of 1 s in the Boolean: z>5 .

2. What is the smallest number greater than 5?

Get a list of numbers greater than 5, then extract the smallest of that list.

No need to find the indexes of the numbers greater than 5. Just use a Boolean list to select ( # ) the numbers from z

<./ (z > 5) # z 6 (z > 5) # z NB. (These are the numbers greater than 5 in z) 9 6 8 9 7 9

3. What is the average value of the numbers that come after a 5?

Get a Boolean list of the position of each 5 , shift this list right one position so it points to the numbers after each 5; select those numbers; find their average.

] after5 =. (|.!.0 list = 5) # list NB. the numbers after each 5 9 3 8 (+/ after5) % # after5 6.66667

4. How many occurrences of the letter 'e' are not followed by another 'e'?

Use methods similar to the previous problem; or you could combine two Boolean lists: get a list telling where there is an 'e', and another telling where there is 'ee', and combine them:

word =. 'eleemosynary' 'e' = word NB. locations of 'e' 1 0 1 1 0 0 0 0 0 0 0 0 'ee' E. word NB. locations of 'ee' 0 0 1 0 0 0 0 0 0 0 0 0 ('e' = word) > ('ee' E. word) NB. 'e' but not 'ee' 1 0 0 1 0 0 0 0 0 0 0 0 +/ ('e' = word) > ('ee' E. word) NB. how many of them? 2