Defining pickrandom


The function of pickrandom is to select either an element at random from a list or a character at random from a word. The procedure will be defined as taking one input called :thing to underline its willingness to accept objects of any type. A user of the procedure will therefore say, for example, pickrandom "bottle to have returned one letter at random from the word "bottle or pickrandom :shopping to have returned some one item from a previously set up list called "shopping.

Breaking the problem down

It is easiest to get to grips with the definition of pickrandom by exploring step by step the various sub-tasks which it is required to handle. This will take a little time but the details are worth digesting.

Before you sit down to define any procedure like pickrandom, which in essence parallels or replicates some human activity, it is always worth stopping to think about how you yourself go about the equivalent task. What seems to be neccessary for picking one object 'randomly' from a set, is first to decide on some characterisation of the objects which allows unique identification of each member of the set and then to adopt some arbitrary technique which is able to pinpoint - in an unprincipled way as far as the objects themselves are concerned - one such particular characteristic. Even when you put your hand into a lucky dip determined to let fate have its way, you will inevitably be using some criterion like 'The first thing my hand touches now as I move it down inside the bag.' or 'The packet nearest my left thumb when I have finished counting to 10'. At a very general level, then, there are two different tasks to cope with in random selection. First there is the act of selection itself. We need to be able to select an element from a set given some identifying characteristic. And secondly we need to be able to arrive at that identifying characteristic in some arbitrary fashion. Let us make a start by approaching the problems in that order.

1. Selecting an item by position

When we deal with words and lists - as opposed to bran tubs - we are dealing with sequentially organised structures. From a general point of view, perhaps the most natural unique identifier for an element in a structure of this sort is its numerical position counting from the left. As you have already discovered, LOGO itself adopts this viewpoint in providing the primitives first and last. More to the point, it also provides a similarly based primitive called item which it seems sensible to take advantage of in the design of pickrandom. Item is an operation requiring two inputs - a number and a word or list. It outputs the element of the word or list found in the position identified by the number. Item 2 "cat, for example, outputs "a and item 3 [a [b c] [d e] ] outputs [d e]. As long as you can specify the object of which it forms a direct constituent and its numerical position within that object, item will extract any element from within any LOGO word or list.

2. Choosing a random position

If our plan is to make use of item's capabilities then clearly - given the way it works - all we need to do now in order to guarantee a random rather than a predetermined selection from its second input, is to ensure that item's first input is a number chosen by some arbitrary technique, a number chosen at random. In other words, putting the ideas together half in LOGO, half in English, we can assume a definition of pickrandom which reads (schematically) as:

to pickrandom :thing
op item (some random number or other) :thing

All the randomness of this procedure is located in the choice of position. Once a position index is established item will select in its normal way the object in the corresponding position.
Generating a number randomly in LOGO is not difficult. But for our purposes that number must identify a position within a LOGO object and must therefore start at a particular value and be within a particular range. Before we can get around to replacing the English phrase of our definition schema by a genuine LOGO expression we need once again to tackle the sub-problems step by step.

2.1. Random numbers (using random)

Random (or pseudo random) number generation in LOGO is catered for by a primitive called random. This is an operation taking one input. If you give random an integer N it will return 'randomly' any one of N consecutive integers. From a human point of view its behaviour is strange, however. The range of integers from which it makes a slection always begins at zero. If you give random the number 4, it is true that you will get any at random one of four whole numbers, but the numbers will be 0 or 1 or 2 or 3. If you say random 12, you are returned some unpredictable integer between 0 and 11.

2.2. Setting the start of a random number range

Random's behaviour would perhaps not be a problem if item behaved in the same way. Unfortunately, item, like us, starts counting from 1. It assumes that the first element of an object occurs in position 1. Item 0 :some.word will incite LOGO to complain: ITEM DIDN'T LIKE 0 AS INPUT. Fortunately, although random itself counts from zero it is a simple matter to adjust the output it provides so that the range of random numbers we are operating with begins at whatever integer we wish. All that is required is to add a number to (or subtract a number from) the output. Adding one to pickrandom 4 will give 1+0 or 1+1 or 1+2 or 1+3. Taking 2 from pickrandom 10 will give some number between 0-2 and 9-2 (i.e. some one of the 10 random integers from -2 through 7). In general, adding or subtracting a number - let us call it 'start' - from the output of random, where 'range' is the value of the input to random, will give us at random any one of 'range' numbers starting with 'start'.

2.2.1. Addition and subtraction in LOGO

To implement this idea you need, of course, to know how to add and subtract in LOGO. It will hardly come as a surprise that the primitives for adding and subtracting are written as + and -. These are both operations which take two numbers as inputs, but for our benefit - though abnormally for LOGO - they are written BETWEEN their two inputs. The LOGO expression for 1 + 1 is thus also 1 + 1. In like manner 1 + random 3 is a correctly formed expression which will output randomly 1 or 2 or 3.

The primitives + and - are not only unusual in their syntax; it is also unfortunately necessary to be aware that as a LOGO line is processed by the interpreter these operations take precedence over the more normally placed procedures in the sense that they are dealt with first. 1 + random 3 must be evaluated as indicated above since there is nothing for 1 to be added to until random 3 is itself evaluated. But when you try random 3 + 1, you will find that 3 is added to 1 first and it is the resulting 4 which is then taken as the input to random with quite different results. It is possible to override the precedence assumed by the interpreter by using parentheses in the manner which you no doubt know from mathematics. Any complete LOGO expression may be enclosed between round brackets and the evaluation of complex expressions with multiple parentheses is handled by working progressively from the innermost sub-expressions outwards. It is possible therefore to write (random 3) +1 as an equivalent to 1 + random 3, if for any reason you prefer that order.

(For a little more info on mathematical and logical operations, look here.)

2.3 Setting the top of a random number range

Just as the bottom of the random number range must not be less that 1 if we are to avoid complaints from item, so too the top of the range cannot be a number higher than the number of elements making up the object we need to pick randomly from. In other words it is not possible to cross your fingers and say 1 + random 2000 in the hope that a length of 2000 will be big enough to cope with any object we are likely to meet. Try item 3 "oh and you will get OH ISN'T LONG ENOUGH TO GET ITEM 3. What is evidently needed is to give random as its input a number which is exactly equivalent to the length of the word or list involved. Since this cannot be known in advance of pickrandom itself receiving an input, it will need to be computed on the spot. The LOGO primitive count is provided for just this purpose. Count :thing returns the number of elements directly constituting :thing (i.e the immediate constituents of :thing regardless of whether or not they themselves have complex internal structure). Count [a [b c] d [e f]] thus returns 4, and count "elephant returns 8.

We are now in a position to spell out the details of the expression which we identified as some random number in the schematic version of pickrandom. Given the general pattern we arrived at above for expressions which output random numbers conforming to fixed start and range values - i.e start + random range - if the input to pickrandom is called "thing, then a random number within an appropriate range will be returned by the expression 1+ random count :thing

With this technique for arbitrarily selecting a position sorted out we can now finally replace the English words some random number in the schema op item (some random number) :thing in order to complete an all-LOGO definition of pickrandom:

to pickrandom :thing
op item (1+ random count :thing) :thing

The parentheses around the expression which outputs the random number are not necessary. But leaving them in does no harm, and it helps to make sense of the two occurrences of :thing. One is an input to count (which establishes the range), the other is an input to item (to identify the object in which the item must be found).

The following diagram for pickrandom's single instruction shows directly how the constituent primitives interact:

If we now suppose that pickrandom is called with an input "cat - i.e pickrandom "cat - so that :thing is assigned the value "cat, and if we further suppose that random 3 on this particular occasion outputs 2, the question marks (the unknowns) in the diagram can be eliminated to show how the instruction as a whole would result in the procedure outputting the word "t.

Phew! Things can only get better!

Ron Brasington
Department of Linguistic Science
The University of Reading