The variable preceded by "??" in the above example matched a segment of the list. We can also use a variable to match a single element of a list, and have that element assigned as its value. For example, here is a way of getting the third element of a list assigned to the variable "item". We use "=" as an anonymous pattern element to match exactly one element of the datum without saving the value and "?item" to match one element and save the value in the variable item.
vars item; [ the cat sat on the mat] matches [ = = ?item ==] => ** <true> item => ** satHere we use the matcher to extract the third and fourth elements of a list:
vars third, fourth; [the cat sat on the black mat] matches [= = ?third ?fourth ==] => ** <true> third => ** sat fourth => ** on
Consider how to define a procedure that searches down a list looking for a given item, and if it finds it returns the next item. You could write that using normal list processing procedures as follows:
define next_item(item, list) -> next; repeat if list = [] then false -> next; return(); elseif hd(list) = item then ;;; found the target, get the next item and stop hd(tl(list)) -> next; return() else ;;; move one step down the list. tl(list) -> list; endif endrepeat enddefine;Here is a version using the pattern matcher.
define next_item(item, list) -> next; vars found; ;;; this is to be used as a pattern element if list matches [ == ^item ?found ==] then found -> next else false -> next endif enddefine;Note that we use "
^
item" as explained previously to insert the value of
the variable item in the pattern. This means that instead of our
programs always having fixed patterns they can have dynamically
constructed patterns.
Now test the procedure
vars person = [name sue age 30 job teacher home york]; next_item("age", person) => ** 30 next_item("home", person) => ** york next_item("height", person) => ** <false>That example should illustrate how much easier it is to use the matcher than ordinary list processing in such cases. Programs using the standard list processing method will run faster, however. If that is important, program using the matcher can be "translated" after they have been developed.
Using the above example as a template produce a definition of a procedure called previous_item that behaves thus:
vars person = [name sue age 30 job teacher home york]; previous_item(30, person) => ** age previous_item("york", person) => ** home previous_item("height", person) => ** <false>