Now while such an output might be appropriate as a way of providing representations of permissible allophones (or at any rate phones) in a given language, it cannot provide for the representation of phonemes, whose feature matrices (if they are to capture the contrastive possibilities of the language) must be free of all redundancies.
[[+syll] [+son +voice -str]]
The first element of each such sub-list provides the structural description of the rule, i.e. it specifies the feature(s) a bundle must contain if it is to be modified. The second element, which lists the predictable features to be removed, determines the structural change.
Arguably the feature redundancies could be even more economically expressed using the following format:
[[+syll] [son voice str]]
which might be read as Values of the features sonorant, voice and strident are redundant in syllabic phonemes. But at this stage we will restrict changes to the WFC format to the minimum in order to emphasize the fact that effectively the same set of conditions may be used (with different interpretations) by either feature insertion or feature removal algorithms. The only change you may have noticed by comparison with the format used in the segment building system is that the second element of the condition has been reduced to a single flat list rather than maintain the more heavily structured pattern, [[+syll][ [+son +voice -str]]]. (For present purposes, any embedding of the list of features to be changed in a yet higher level list is quite pointless given that no choice is ever available in the features to be removed and that as a result pickrandom is not required.)
Despite the limitations accepted here, you will none the less find it interesting to experiment with the economical specification of feature redundancies suggested above. You might also consider rewriting your segment building system so that the two types of conditions - one governing the insertion of distinctive features, the other the insertion of non-distinctive (redundant, predictable) features - are clearly separated, differently formatted and applied by different algorithms. In this way precisely the same set of conditions - identical data structures - could be used to control feature insertion and feature deletion.
Since the intended output such a procedure is a phonemic representation, we might as well call the procedure phonemicize. It will clearly be recursive and will require two inputs:
to phonemicize :segment :conditions if empty? :conditions [op :segment] if subset? first first :conditions :segment [op phonemicize ( killoff last first :conditions :segment) bf :conditions ] op phonemicize :segment bf :conditions endAt any stage, what we have called the current condition is first :conditions.
The structural description of the corresponding rule is therefore first first :conditions and the test for a match is provided by subset? first first :conditions :segment.
The structural change - the removal of the last first :conditions from :segment - is handled by a subordinate procedure called killoff, which, of course, needs to be defined. Notice that it is killoff, in the parenthesized expression, which provides the first input to next clone of phonemicize by outputting a modified form of :segment.
to remove :old.item :list if empty? :list [op ] if :old.item = first :list [op bf :list] op fput first :list remove :old.item bf :list endThe problem is that remove removes - or attempts to remove - input 1 as a single object from input 2. Killoff, by comparison, must remove each of the elements of input 1 individually from input 2. Suppose input 1 is [@son @voice], killoff must remove @son and @voice separately from input 2, not least because input 2 - as a flat list - could not possibly contain anything like a sub-list [@son @voice].
This does not mean, however, that we give up all ideas of exploiting remove. What it means is that if we are to take advantage of this ready made procedure, we must find some way to apply it recursively, working through each of the elements of the list of old.items turn by turn. This is where killoff comes in. Killoff is a recursive higher level parent of (the already recursive) remove which nibbles its way through an old items list (:old.items) passing on to each clone a second input (representing a feature bundle) already modified by one application of remove:
to killoff :old.items :list if empty? :old.items [op :list] op killoff bf :old.items remove first :old.items :list end(Killoff as defined here is specifically tied to the running of remove. For a more general approach to this kind of problem look here.)
phonemicize possible.segment :conditions
To get anything like sensible results from the system you will obviously need to work on the contents of :conditions to make it reflect the constraints in some particular language. if you do this, you will realise that there is some considerable duplication of activity between the linguistic facts represented on the one hand by the filters (which will, let us suppose, disallow [@nas !voice]) and the conditions (which, in the same circumstances, will include [[@nas] [@voice]] ). Saying the same thing twice, even if expressing it differently, is not a good idea. The segment building system, especially if made to distinguish the insertion of distinctive features from the other the insertion of non-distinctive features, is from this point of view arguably preferable.