LISP - Chaining Predicates
Lisp - Modern Predicate Logic
Section titled “Lisp - Modern Predicate Logic”In Lisp, a predicate is a function that tests a condition and returns a generalized boolean value: T (true) or NIL (false). Chaining predicates allows you to build complex logic from simple, reusable tests. This is a core technique in functional programming that leads to clear and maintainable code.
Logical Operators: and, or, not
Section titled “Logical Operators: and, or, not”The primary tools for combining predicates are the logical operators, which feature short-circuiting evaluation:
and: Evaluates forms from left to right. Stops and returnsNILas soon as any form returnsNIL. If all forms evaluate to true, it returns the value of the last form.or: Evaluates forms from left to right. Stops and returns the first non-NILvalue it encounters. If all forms evaluate toNIL, it returnsNIL.not: Takes a single argument. ReturnsTif the argument isNIL, andNILif the argument is anything other thanNIL.
Example: Defining a Complex Predicate
Section titled “Example: Defining a Complex Predicate”Instead of writing one-off checks, it’s a best practice to encapsulate complex logic in a dedicated predicate function. Let’s create a function to check if a number is a positive even integer.
main.lisp
Section titled “main.lisp”(defun positive-even-p (x) "Predicate that returns T if X is a positive and even integer, otherwise NIL." (and (integerp x) ; Is it an integer? (plusp x) ; Is it positive? (more idiomatic than (> x 0)) (evenp x))) ; Is it even?
;; --- Test Cases ---(format t "Is 10 a positive even number? ~a~%" (if (positive-even-p 10) 'Yes 'No))(format t "Is 11 a positive even number? ~a~%" (if (positive-even-p 11) 'Yes 'No))(format t "Is -4 a positive even number? ~a~%" (if (positive-even-p -4) 'Yes 'No))(format t "Is 'hello a positive even number? ~a~%" (if (positive-even-p 'hello) 'Yes 'No))Output
Section titled “Output”Executing the code produces the following clear output:
Is 10 a positive even number? YesIs 11 a positive even number? NoIs -4 a positive even number? NoIs 'hello a positive even number? NoHigher-Order Functions for Sequence Predicates
Section titled “Higher-Order Functions for Sequence Predicates”Lisp provides powerful higher-order functions that apply predicates to sequences (like lists or vectors). This is a cornerstone of the functional style.
every: ReturnsTif the predicate is true for every element in a sequence.some: Returns the first non-NILresult if the predicate is true for at least one element.notany: ReturnsTif the predicate is false for all elements.notevery: ReturnsTif the predicate is false for at least one element.
Practical Example: Validating a Dataset
Section titled “Practical Example: Validating a Dataset”Imagine you have a list of sensor readings and you want to validate that all readings are valid numbers within an acceptable range.
main.lisp
Section titled “main.lisp”(defun valid-reading-p (reading) "Predicate to check if a sensor reading is a number between 0 and 100." (and (numberp reading) (>= reading 0) (<= reading 100)))
(let ((dataset-a '(78 92 100 65)) (dataset-b '(88 95 101 70)) ; Contains an out-of-range value (dataset-c '(66 'error 93))) ; Contains a non-numeric value
(format t "Is dataset A valid? ~a~%" (if (every #'valid-reading-p dataset-a) 'Yes 'No)) (format t "Is dataset B valid? ~a~%" (if (every #'valid-reading-p dataset-b) 'Yes 'No)) (format t "Is dataset C valid? ~a~%" (if (every #'valid-reading-p dataset-c) 'Yes 'No)))Output
Section titled “Output”This demonstrates a practical and readable validation check:
Is dataset A valid? YesIs dataset B valid? NoIs dataset C valid? No