Let us continue where we left off last time.

## List Patterns

If the incoming argument is a list, then we can use two types of list patterns to match the list elements, namely, list and list*.

(match ‘(a b c)

((list ‘a ‘b X) X))

=> c

This list pattern begins with the list keyword. After that you can specify either the actual elements in the list or variables. If a variable is specified, it will match exactly one element of the list. In this example, we expect two elements ‘a and ‘b followed by any element. As expected, the variable X matches the element c in the argument.

(match ‘(a b)

((list ‘a ‘b X) (print X)))

=> nil

Here the pattern looks for a 3 element list, and so it fails.

You can use the convenient backquote mechanism for list matching:

(match ‘(a b c)

(`(a b ,x) x))

=> c

This saves a few keystrokes and makes it more readable. Note that you have to use the comma before a variable to mark it as a variable.

The second type of list pattern uses the keyword list*. It allows the use of variables as in the other type, but the last variable will match multiple elements of the incoming list.

(match ‘(a b c d)

((list* ‘a ‘b X ) X))

=> (c d)

You can see that variable X matches the last 2 elements of the argument.

(match ‘(a b c d)

((list* X ‘b ‘c Y) Y))

=> (d)

Here we have 2 variables and Y matches the last (trailing) arguments. Consider this case:

(match ‘(a b c d)

((list* ‘a ‘b ‘c ‘d X ) t))

=> t

Here the variable X will be bound to an empty list. You can replace a variable by an underscore if you don’t need the binding:

(match ‘(a b c d)

((list* ‘a ‘b ‘c ‘d _ ) t))

=> t

Consider the following examples of an empty list as supplied argument:

(match ‘()

((list* _) t)) ;

=> t

(match ‘()

((list* X) t))

=> t

We can use backquote as we did earlier, with a slight difference:

(match ‘(a b c d)

(`(a b ,@x) x))

=> (c d)

“,@” denotes a list, since this is a multi-value match.

It is worthwhile to  compare list and list* patterns using a common example:

(match ‘(p q r s)

((list ‘p ‘q ‘r ‘s) t))

=> t

(match ‘(p q r s)

((list* ‘p ‘q ‘r ‘s) t))

=> nil

(match ‘(p q r s)

((list* ‘p ‘q ‘r (list ‘s)) t))

=> t

(match ‘(p q r s)

((list* ‘p ‘q ‘r x) x))

=> (s)

Notice how list* has the last element as a list.

## Property Lists

If you have a list of key and value pairs, then you can use the plist pattern to match the same.

(match ‘(:name “Peter” :age 45 :gender “Male” :country “India”)

((plist :name N :gender G :age A) (list N G A)))

=> (“Peter” “Male” 45)

Notice that the order is not important here, and you can match any subset.

## Assoc Lists

Optima supports pattern matching in assoc lists, as in list of pairs. See the following examples.

(match ‘((a . 1) (b . 2) (c . 3))

((assoc b x) x))

=> 2

(match ‘((a . 1) (b . 2) (c . 3))

((and (assoc a x) (assoc b y) (assoc c 3)) (+ x y)))

=> 3

(match ‘((a 1) (b 2) (c 3))

((and (assoc a x) (assoc b y) (assoc c z)) (list x y z)))

=> ((1) (2) (3))

(match ‘((a 1) (b 2) (c 3))

((and (assoc a (list x)) (assoc b (list y)) (assoc c (list z))) (list x y z)))

=> (1 2 3)

Hope you can see the difference between using a dotted pair versus a 2-element list.

We have covered quite a bit in this post, and it is time to take a break. In the next post, I will show how to apply these ideas in Opusmodus.

Tags: ,