These exercises ask you to write extensions to match.lisp. To do them, load the matcher like this:

Note: This matcher is the basis of the matcher used by the Lisp Critic. It does CAR/CDR matching of lists. This is different than the matching logic for JSON-like lists of properties.

(ql:quickload "match")

This creates two packages:

To do the exercises

The exmatch package already exports the names of the functions to be defined for the exercises.

To test any particular exercise, just run the tests for that specific pattern extension. But before submitting your answers, do (run-tests) with no arguments, to run all the match tests. Make sure that all tests pass, except those for any exercise you haven't done yet.

A few examples are given here of each extension, but there are far many more tests in match.lisp. Study those tests before coding an answer. Also study how the existing extensions, such as ?and and ??, work as well.


MATCH-OR, MATCH-NOT, MATCH-=

Match bundle

Define the pattern function ?or such that the pattern (?or pattern1 pattern2 ...) returns bindings for every pattern that matches the input.

> (match-p '(?or a b) 'b)
(NIL)
> (match-p '(?or a b) 'c)
NIL
> (match-p '(?x ?y (?or ?x ?y ?z)) '(a b a))
(((?Y . B) (?X . A)) ((?Z . A) (?Y . B) (?X . A)))

Define the pattern function ?not such that the pattern (?not pattern) matches an input if and only if pattern does not match that input.

> (match-p '(?not a) 'a)
NIL
> (match-p '(?not b) 'a)
(NIL)
(match-p '(?not ?x) 'a)
NIL
> (match-p '(?x (?not ?x)) '(a b))
(((?X . A)))

Note that some of the test cases for ?not require ?or to be defined first.

The matcher already defines (?? function) to return a match if function returns true for the object, e.g., (?? numberp) will match any number. Additional arguments to the function can be specified in the pattern, e.g., (?? > 5) will match anything greater than 5. This exercise asks you to define ?= to match a pattern to the result of applying a function to the object. The syntax is (?= pattern function argument1 argument2 ...). When this is matched against an object, it first calls (function object argument1 argument2 ...), and then matches pattern against the result.

> (defun square (x) (* x x))
SQUARE
> (match-p '(?= ?x square) 3)
(((?X . 9)))
> (defun add-title (name title) (cons title name))
ADD-TITLE
>(match-p '(?= ?name add-title professor) '(john smith))
(((?NAME PROFESSOR JOHN SMITH)))

MATCH-CONTAINS

Match bundle

Define the pattern function ?contains such that the pattern (?contains pattern) matches an input if and only if pattern matches the input or some subexpression of the input.

Note: the order of variable bindings doesn't matter.
> (match-p '(?contains ?x) 'a)
(((?X . A)))
> (match-p '(?contains (?and (?? numberp) ?x)) '((a 12) c (((5)))))
(((?X . 5)) ((?X . 12)))