REDUCE

4.3 Property List Functions

A property list is used to associate an id with a set of entities; those entities are called flags if their use associates a boolean value with the id, and properties if the id is to be associated with an arbitrary attribute.

(put U:id IND:id PROP:any): any expr
The indicator IND with the property PROP is placed on the property list of U. If the action of put occurs, the value of PROP is returned. If either U or IND are not ids then a type mismatch error occurs.
    ⋆⋆⋆⋆⋆ An attempt was made to do PUT on ‘U', which is not  
    an identifier

The definition of a property will cause the previous definition to be lost.

(get U:id IND:id): any expr
Returns the property associated with indicator IND from the property list of U. If U does not have indicator IND, nil is returned. Get returns nil if U is not an id.

(deflist U:list IND:id): list expr
U is a list in which each element is a two-element list: (ID:id PROP:any). Each id in U has the indicator IND with property PROP placed on its property list by the function put function. The value of deflist is a list of the first elements of each two-element list.
    1 lisp> (deflist '((plus2 'two)  
                       (plus 'many))  
                     'no-operands)  
    (plus2 plus)  
    2 lisp> (get 'plus 'no-operands)  
    many

(remprop U:id IND:id): any expr
Removes the property with indicator IND from the property list of U. Returns the removed property or nil if there was no such indicator.

(rempropl U:id-list IND:id): nil expr
Removes the property IND from all of the ids in U.

The following example is intended to illustrate the idea of data driven programming. We define a function called simplify which will simplify symbolic algebraic expressions. These expressions are represented as lists. To begin, there will be only one operator (plus), and operands may be integers, variables or an application of plus. Prefix notation is used. The addition of variable x and 3 would be represented as (plus x 3). The first version of simplify will certainly do the job.

(de simplify (expression)  
  (cond ((atom expression) expression)  
        ((eq (first expression 'plus)  
             (add-simplify expression))  
        (t expression)))

However, as we add operands it will become necessary to redefine simplify. A better approach is to allow the operator to specify the information on how to simplify the expression.

(de simplify (expression)  
  (cond ((atom expression) expression)  
        (t (apply (get (first expression) 'simplify)  
                  (ncons expression)))))

(put 'plus 'simplify 'add-simplify)

This version will not have to be rewritten when a new operator is added. For example, if the operator times is added then we only need to define a function called times-simplify and attach its name to the property list of times under the indicator simplify. We can design add-simplify in a similar fashion. Using this approach we will be able to accomodate numbers other than integers.

  (de add-simplify (expression)  
    (let ((left (second expression))  
          (right (third expression)))  
      (cond ((zerop left) right)  
            ((zerop right) left)  
            ((and (numberp left)(numberp right))  
             (let ((new (common-type left right)))  
               (apply (get (data-type (first  new))'add-op) new)))  
            (t (list (first expression)  
                     (simplify left)  
                     (simplify right))))))

(put 'integer 'add-op 'plus2)

1 lisp> (simplify '(plus (plus 1 8) (plus x 0)))  
(plus 9 X)

4.3.1 Functions for Flagging Ids

(flag U:id-list V:id): nil expr
Flag flags each id in U with V; that is, the effect of flag is that for each id X in U, (flagp X V) has the value t. Both V and all of the elements of U must be identifiers or a type mismatch error occurs. The id V will appear on the property list of each id in U. However, flags cannot be accessed, placed on, or removed from property lists using the normal property list functions get, put, and remprop. Note that if an error occurs during execution of flag, then some of the ids in U may be flagged with V, and others may not be. The statement below causes the flag Lose to be placed on the property lists of the ids x and y.
    (flag '(x y) 'lose)

(flagp U:id V:id): boolean expr
Returns t if U has been flagged with V; otherwise returns nil. Returns NIL if either U or V is not an id.

(remflag U:id-list V:id): nil expr
Removes the flag V from the property list of each member of the list U. Both V and all the elements of U must be ids or the type mismatch error occurs.

(flag1 U:id V:any): Undefined expr
The identifier U is flagged V. The effect is to add V to the property list of U.

(remflag1 U:id V:any): Undefined expr
The identifier U is no longer flagged V. The effect is to removed V from the property list of U.

4.3.2 Direct Access to the Property Cell

Use of the following functions can destroy the integrity of the property list. Since PSL uses properties at a low level, care should be taken in the use of these functions.

(prop U:id): any expr
Returns the property list of U.

(setprop U:id L:any): L:any expr
Store item L as the property list of U.