
The peaks and troughs of sonority derive, of course, from the individual sonority characteristics of the sounds which are strung together to make up the word. In general, vowels are relatively high in sonority and make up the centres of syllables, while consonants are relatively low in sonority and occur in the margins. But, not surprisingly, when we look more closely, we can make finer disinctions. Of the vowels, /a/ is more sonorous than /i/ and amongst the consonants /l/ and /n/ are more sonorous than /b/ and /d/. In other words, the sounds of speech can be arrayed along a scale of sonority. Within a syllable, as we move from the margin to the centre and then back to the margin again, we typically find that the constituent sounds are arranged, in accord with their individual characteristics, in a regularly ascending then descending pattern of sonority. A detailed 'trace' of blend would, therefore, look like this:

For now, suppose that we plan only to build a syllable counter. Suppose too that we are prepared to accept, without dissent, the proposal that the sonority ranking of English sounds is - in part - as follows:
(p, t, k) (b, d, j, g) (f, s) (v, z ) (m, n) (l, r) (h) (y, w) ( i, u) (e, o, 3) (a )
The 11-point scale goes (left to right) from lower to higher, with equally ranked sounds enclosed in the same set of parentheses. A number of sounds have been omitted to avoid the problems of dealing with phonetic sysmbols at this stage. (The number 3 is included, however, to stand for the vowel in the first syllable of phonology.
The sonority scale presented above has almost already the appearance of a Logo object. Suppose we make that ressemblance explicit and treat the scale directly as a list of lists:
make "sonority.scale [ [p t k] [b d j g] [f s] [v z] [m n] [l r] [h] [y w] [ i u] [e o 3] [a ] ]
The members of the first sub-list of scale can be taken to have sonority value 1, the members of the second, sonority value 2 and so on.
The connection between this discussion and the notions of non-numerical targets and input modification in recursive procedures should now be emerging clearly enough. Suppose that the procedure sonority is provided with 3 inputs - not only with :segment but also with an input called :scale (initially the full :sonority.scale) and a 'counter' called :value (initially 1). The first incarnation of sonority will look to see if :segment is a member of first :scale. If it is, it outputs :value, i.e. it outputs 1. If :segment is not a member of first :scale, then a recursive wind through :scale begins. As many recursive calls as necessary are made, with each clone being given a be-headed version of the preceding clone's :scale and a new version of :value (incremented by 1), until some clone somewhere along the line finds a sublist containing :segment in first :scale. At that point, the value of :value will correspond to the sonority of :segment and can be immediately output.
to sonority :segment :scale :value if member? :segment first :scale [op :value] op sonority :segment bf :scale :value + 1 endThis technique of nibbling away at list from the head (or indeed from the tail) is one of the most characteristic features of recursive list processing. Notice, however, an inherent danger in this tactic which needs to be guarded against.
First set up :sonority.scale, and copy and define sonority. Now run sonority offering "q as the value for :segment. Clearly, there is no way that the procedure's terminating condition can be met since "q is not a member of any sub-list of :scale. Instead you end up with an error message. At level 12 of the recursion - remember that there are only 11 points in the scale - the poor sonority clone who is trying to find first :scale, tries first on an empty list. Unfortunately, in Logo there is no such thing as the first element of an empty list. What is needed, then, is a fall-back target which can always be achieved. A test for an empty list, right up front, is more often than not the safety net you need to provide. If we suppose that, in the case of sonority, the appropriate value to be output when a segment is not found is zero, then this modification will fix the problem:
to sonority :segment :scale :value if empty? :scale [op 0] if member? :segment first :scale [op :value] op sonority :segment bf :scale :value + 1 end
We have also tied together the ideas of input modification and target, choosing examples in which the target (the terminating condition) is eventually met as the result of an input being modified on the recursive call. This is perhaps normally the case, but not necessarily so. In sonority the variation in one input has nothing to do with the terminating conditions. True, there is no contradiciton in that. But you may also find procedures in which a target is met independently of whatever happens to the procedure inputs. Outside events - like movements of the hands of a clock in the following familiar scenario - may assume control. If the first terminating condition is met, it matters little how many questions been answered.
to sit :examination.questions if time.up? [stop.writing] if empty? :examination.questions [go.home] answer first :examination.questions sit bf :examination.questions end
E-mail: ron.brasington@rdg.ac.uk