Pattern Matching with Optima Lisp Library – Part 2

Written by on June 17, 2016 in LISP, Programming with 0 Comments

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: ,

Subscribe

If you enjoyed this article, subscribe now to receive more just like it.

Subscribe via RSS Feed

Leave a Reply

Your email address will not be published.

Top